T2 Game 题解

· · 题解

为了方便,设 p_i 表示当前满足 a_k=ik 的值。交换两个位置 ij 表示交换 a_ia_j(此时 p_{a_i},p_{a_j} 也会更新)。

首先考虑 t\le 2 的情况。

如果 t=1,先手一定会交换第一个满足 a_i\ne i 的位置 i 和后面的位置 p_i,这样可以做到字典序最小。

如果 t=2,先考虑第二步后手会干什么。类似上面 t=1 时先手的策略,后手会交换此时第一个满足 a_i\ne n-i+1 的位置 i 和后面的位置 p_{n-i+1}

接着考虑先手:

代码模拟,不难做到 \mathcal{O}(n)

现在考虑 t>2 的情况。

对于 2\nmid t,答案和 t=1 时答案一样。因为先手先按最优完成第一步后,a_1 必然为 1,这样就和前面 t=2,a_1=n 的情况是一样的:此时后手的最优策略只能是把位置 1 再移走,否则先手可能在下一步又找到一个字典序更小的方法。如果后手把位置 1 移走了,后面先手就只能选择撤销后手的操作。

对于 2\mid t,类似的,和 t=2 答案一样。可以把这种情况看成先手先操作一步,接着后手变成新的“先手”,进行 t'=t-1 次操作,最终“先手”的目标是字典序最大,“后手”的目标是字典序最小。由前面同理可得,2\nmid t' 的这种情况相当于 t'=1 的情况。因此 2\mid t 也就相当于 t=2 的情况。

那么就可以把 t 的范围缩小成 \le 2,再用上面的方法解决。总复杂度 \mathcal{O}(n)

#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;
}