cf1427 D. Unshuffling a Deck

题意:

给定一个排列。每次操作把数组分成段 \([1,r_1],[r_1+1,r_2],\cdots ,[r_k+1,n]\) ,然后所有段之间翻转,段内元素顺序不变。构造一种操作次数不大于 n 的方案使数组有序。

\(n\le 52\)

思路:

假设有一段是已经有序的,初始为空,在数组首或者数组尾。从1 到 n,每次往有序段中加一个数。如果有序段本来在数组首,操作后有序段会跑到数组尾,反之同理。这样操作 n 次后数组一定有序

初始有序段在数组首还是尾跟 n 的奇偶性有关

const signed N = 55;
int n, a[N], p[N]; vector<vector<int>> ans;

void work(vector<int> &ve) {
    static int t[N];
    int ed = n, idx = 0;
    reverse(all(ve)); for(int len : ve) {
        for(int i = ed-len+1; i <= ed; i++)
            t[++idx] = a[i];
        ed -= len;
    }
    memcpy(a, t, sizeof a);
    for(int i = 1; i <= n; i++) p[a[i]] = i;
}

signed main() {
    iofast;
    cin >> n; for(int i = 1; i <= n; i++)
        cin >> a[i], p[a[i]] = i;
    
    if(n % 2) p[0] = n + 1; else p[0] = 0;
    for(int i = 1, now = n%2; i <= n; i++, now ^= 1) {
        vector<int> res;
        for(int j = 1; j < i; j++) res.pb(1);
        res.pb(abs(p[i]-p[i-1]));
        if(i-1+abs(p[i]-p[i-1]) < n) res.pb(n-(i-1+abs(p[i]-p[i-1])));

        if(res.size() == 1) continue; //题目规定这种不输出
        if(now) reverse(all(res));
        ans.pb(res);
        work(res);
    }

    cout << ans.size() << endl;
    for(vector<int> &res : ans) {
        cout << res.size();
        for(int i : res) cout << ' ' << i;
        cout << endl;
    }
}
posted @ 2022-04-26 10:41  Bellala  阅读(51)  评论(0)    收藏  举报