专栏文章

题解:CF2101B Quartet Swapping

CF2101B题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minzws80
此快照首次捕获于
2025/12/02 11:05
3 个月前
此快照最后确认于
2025/12/02 11:05
3 个月前
查看原文
首先我们注意到奇数位和偶数位是独立的,将其分开考虑。我们考虑贪心地从前向后要求每一位最小,也就是从小到大枚举 ii,将与第 ii 位奇偶相同的最小值移动到第 ii 位上,然后将其删去。
nn 为当前剩余的数字数量,最小值在第 jj 位上。我们发现如果 jnj \neq n,直接向前交换即可;但是 j=nj = n 较为麻烦,我们考量这样一个示例
[5,4,3,1,2][5,1,2,4,3][2,4,5,1,3][5, 4, 3, 1, 2]\\ [5, 1, 2, 4, 3]\\ [2, 4, 5, 1, 3]\\
我们发现对于 n3n - 3 进行一次操作即可,这样可以将 jjnn 调整到 n2n - 2
使用链表维护 O(1)\mathcal{O}(1) 交换、删除。一共有 nn 次找最大值的操作,共 O(n)\mathcal{O}(n) 次交换,时间复杂度 O(n)\mathcal{O}(n)
Code:
CPP
#include<bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))

using namespace std;

const int maxn = 2e5 + 10;

int t, n;
int a[maxn], nxt[maxn], pre[maxn], ord1[maxn], ord2[maxn];

int main(){
    scanf("%d", &t), a[0] = 1e9;
    while (t--){
        scanf("%d", &n), nxt[0] = 1, fill(ord1 + 1, ord1 + n + 1, 0), fill(ord2 + 1, ord2 + n + 1, 0);
        for (int i = 1; i <= n; i++){
            scanf("%d", &a[i]), pre[i] = i - 1, nxt[i] = i + 1, (i & 1 ? ord1 : ord2)[a[i]] = i;
        }
        const auto cmp = [](int x, int y){return a[x] < a[y];};
        sort(ord1 + 1, ord1 + n + 1, cmp), sort(ord2 + 1, ord2 + n + 1, cmp);
        for (int i = 1, p1 = 1, p2 = 1; i <= n - 3; i++){
            int* ord = i & 1 ? ord1 : ord2, &p = i & 1 ? p1 : p2;
            if (nxt[ord[p]] > n){
                const int q1 = pre[ord[p]], q2 = pre[q1], q3 = pre[q2], q4 = pre[q3];
                nxt[ord[p]] = q3, nxt[q2] = n + 1, nxt[q4] = q1, pre[q1] = q4, pre[q3] = ord[p];
            }
            const int q = nxt[ord[p]];
            nxt[pre[ord[p]]] = nxt[q], pre[nxt[q]] = pre[ord[p]], nxt[q] = nxt[0], pre[nxt[0]] = q, nxt[0] = ord[p], pre[ord[p]] = 0;
            printf("%d ", a[nxt[0]]), pre[nxt[nxt[0]]] = 0, nxt[0] = nxt[nxt[0]], p++;
        }
        for (int i = nxt[0]; i <= n; i = nxt[i]){
            printf("%d ", a[i]);
        }
        putchar('\n');
    }

return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...