Codeforces Round 1015, Div. 1 + Div. 2 C.You Soared Afar With Grace

C.You Soared Afar With Grace

原题链接

Problem Statement

给你一个长度为 n 的排列组合 a 和 b 。您最多可以执行下面的操作 n 次:
选择两个索引 i 和 j ( 1≤i,j≤n , i≠j ),将 ai 与 aj 交换,将 bi 与 bj 交换。
判断 a 和 b 在运算后能否互为相反数。换句话说,对于每个 i=1,2,…,n , ai=bn+1−i .
如果可能,输出任何有效的运算序列。否则,输出 −1 。

Constraints:

输入

每个测试包含多个测试用例。第一行包含测试用例的数量 t ( 1≤t≤104 )。测试用例说明如下。

每个测试用例的第一行都包含一个整数 n ( 2≤n≤2⋅105 ) - 排列的长度。

第二行包含 n 个整数 a1,a2,…,an ( 1≤ai≤n )。

第三行包含 n 个整数 b1,b2,…,bn ( 1≤bi≤n )。
可以保证 a 和 b 是长度为 n 的排列。
保证所有测试用例中 n 的总和不超过 2⋅105

Sample Input:

400

Sample Output:

24

解题思路:

注意到,互为逆序的两个序列最后一定是中心对称的,因此,如果可以将某个a与b相同的位置与
与中心位置互换,又因为每个序列与最终序列逆序对(看下标)个数最多不超过n个,每次交换消除一对,那么最多进行n/2次交换。
最后用一个map维护a种每个数对应的下标,遍历b中元素,将位置pos[bi]与n-i+1模拟交换即可

AC code:

void solve(){
    int n;cin>>n;
    vector<int>a(n+1),b(n+1);
    map<int,int>mp,pos;
    for(int i=1;i<=n;i++) cin>>a[i],pos[a[i]]=i;
    for(int i=1;i<=n;i++) cin>>b[i];
    if(a==b) {cout<<-1<<endl;return;}
    for(int i=1;i<=n;i++){
        if(!mp.count(a[i])) mp[a[i]]=b[i],mp[b[i]]=a[i];
        else{
            if(mp[a[i]]!=b[i]) {cout<<-1<<endl;return;}
        }
    }
    vector<pair<int,int>>toswap;
    for(int i=1;i<=n;i++){
        if(mp[a[i]]==a[i]) {
            int x=i,y=(n+1)/2;
            if(x==y) continue;
            if(x>y) swap(x,y);
            swap(a[x],a[y]);
            swap(b[x],b[y]);
            pos[a[x]]=x;
            pos[a[y]]=y;
            toswap.push_back({x,y});
        }
    }
    for(int i=1;i<=n/2;i++){
        int x=n-i+1,y=pos[b[i]];
        if(x==y) continue;
        if(x>y) swap(x,y);
        swap(a[x],a[y]);
        swap(b[x],b[y]);
        pos[a[x]]=x;
        pos[a[y]]=y;
        toswap.push_back({x,y});
    }
    for(int i=1;i<=n;i++){
        if(a[i]!=b[n-i+1]) {cout<<-1<<endl;return;}
    }//check for right
    cout<<toswap.size()<<endl;
    for(auto &[x,y]:toswap){
        cout<<x<<' '<<y<<endl;
    }
}
posted @ 2025-04-06 12:50  usedchang  阅读(103)  评论(0)    收藏  举报