1 条题解
-
0
自动搬运
来自洛谷,原作者为

cff_0102
& aqua_qaq | 团子群 185800038 | 如果我死了说明我 AFO 了搬运于
2025-08-24 23:11:46,当前版本为作者最后更新于2025-03-23 00:29:11,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
为了方便,设 表示当前满足 的 的值。交换两个位置 和 表示交换 和 (此时 也会更新)。
首先考虑 的情况。
如果 ,先手一定会交换第一个满足 的位置 和后面的位置 ,这样可以做到字典序最小。
如果 ,先考虑第二步后手会干什么。类似上面 时先手的策略,后手会交换此时第一个满足 的位置 和后面的位置 。
接着考虑先手:
- 如果刚开始 ,先手的最优策略显然是将这个数移走,这样后手只能把这个数移回来。否则,后手可能在后面找到一个比原来字典序更大的方案。这样,最终得到的答案会和刚开始的排列完全相同。
- 如果 ,先手不会傻到去交换位置 和 。因此后手的操作肯定是交换先手操作后的位置 和 。可以发现,在这种情况下,等价于后手先交换现在的位置 和 ,先手再按最优方式操作(这个证明比较显然,能够自己理解的可以直接跳过下面一段):
- 如果先手的操作不涉及位置 和 ,那么这两个操作先后显然是无关的。
- 如果先手交换了位置 和 ,后手交换新的位置 和 ,那么现在的情况是位置 变成了 ,位置 变成了 ,位置 变成了 。可以发现这种情况和先交换位置 和 ,再交换(原来的)位置 和 是等价的。
- 先手交换位置 和 的情况同理。
- 因此在这种情况下,可以直接交换位置 和 ,剩下的问题是位置 里面交换两个数使得字典序最小,就变成了前面 时讨论的方法。
代码模拟,不难做到 。
现在考虑 的情况。
对于 ,答案和 时答案一样。因为先手先按最优完成第一步后, 必然为 ,这样就和前面 的情况是一样的:此时后手的最优策略只能是把位置 再移走,否则先手可能在下一步又找到一个字典序更小的方法。如果后手把位置 移走了,后面先手就只能选择撤销后手的操作。
对于 ,类似的,和 答案一样。可以把这种情况看成先手先操作一步,接着后手变成新的“先手”,进行 次操作,最终“先手”的目标是字典序最大,“后手”的目标是字典序最小。由前面同理可得, 的这种情况相当于 的情况。因此 也就相当于 的情况。
那么就可以把 的范围缩小成 ,再用上面的方法解决。总复杂度 。
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int a[N],p[N]; int main(){ ios::sync_with_stdio(0);cin.tie(0); long long t;int n;cin>>t>>n; for(int i=1;i<=n;i++)cin>>a[i],p[a[i]]=i; if(t&1){ for(int i=1;i<=n;i++){ if(a[i]!=i){ swap(a[i],a[p[i]]); break; } } for(int i=1;i<=n;i++)cout<<a[i]<<" "; }else{ if(a[1]==n){ for(int i=1;i<=n;i++)cout<<a[i]<<" "; }else{ p[a[1]]=p[n]; swap(a[1],a[p[n]]); p[n]=1;//这句实际可以删掉 for(int i=2;i<=n;i++){ if(a[i]!=i-1){ swap(a[i],a[p[i-1]]); break; } } for(int i=1;i<=n;i++)cout<<a[i]<<" "; } } return 0; }
- 1
信息
- ID
- 11633
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者