拿个沙发
此题是典型的思维题,且 “思维容易,实现难” 主要是实现比较难想到。

代码如下,具体细节通过注释给出
其中,c 数组记录选中数在 a 中的下标,d 数组记录选中数的值,c 和 d 的配合可以对选出来的离散集合进行排序,通过排序后的结果,依次修改 a 数组和 b 数组。

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;

int a[100009], b[100009], n;

int c[100009], d[100009], vis[100009];

void fu(int l, int r){
    int tot = 0;  memset(vis, 0, sizeof(vis));
    ///   确保前四分之一的数在集合中
    for(int i = l; i <= r; i ++){
        if(!vis[i]) c[++ tot] = i, vis[i] ++;
        if(!vis[b[i]]) c[++ tot] = b[i], vis[b[i]] ++;
    }
    ///   如果不够二分之一的数, 则补足缺少的部分
    for(int i = r + 1; tot < n / 2; i ++)
        if(!vis[i]) c[++ tot] = i;
    ///   打印答案
    for(int i = 1; i <= n / 2; i ++) {
        if(i != 1) cout <<  ' ';
        cout << c[i];
    }   cout << endl;
    ///   利用 c 、d 数组对保存临时值,对离散的集合排序
    for(int i = 1; i <= tot; i ++)
        d[i] = a[c[i]];
    sort(c + 1, c + n / 2 + 1);
    sort(d + 1, d + 1 + tot);
    for(int i = 1; i <= n / 2; i ++)
        a[c[i]] = d[i];
    ///   重置修改后的 b 数组
    for(int i = 1; i <= n; i ++)
        b[a[i]] = i;
}
int main(){
    cin >> n;
    for(int i = 1; i <= n;i ++) {
        cin >> a[i];
        b[a[i]] = i;
    }
    cout << 3 << endl;      /// 三步必定可以成功,先排前四分之一,再排第二个四分之一,最后排最后二分之一
    fu(1, n / 4);
    fu(n / 4 + 1, n / 2);
    for(int i = n / 2 + 1; i <= n; i ++) {
        if(i != n / 2 + 1) cout << ' ';
        cout << i;
    }
    return 0;
}

最后欢迎大家给我指出值得改进的地方。