【裴蜀定理】codeforces 2244 C. Stepan and Permutation
题目
https://codeforces.com/problemset/problem/2244/C
题意
输入 \(T(\leq 1e4)\) 表示 \(T\) 组数据。所有数据的 \(n\) 之和 \(\leq 2e5\)。
每组数据输入 \(n(1 \leq n \leq 2e5)\text{ }x \text{ } y(1 \leq x,y \leq n 且 x+y \leq n)\) 和 1~n 的排列 \(p\)。
你可以执行如下操作任意次:
选择两个下标 \(i\) 和 \(j\),满足 \(|i-j| = x\) 或者 \(|i-j| = y\),然后交换 \(p[i]\) 和 \(p[j]\)。
能否把 \(p\) 排成升序?输出 YES 或 NO。
进阶:做到 O(1) 空间。
题解
一个下标位置 \(i\) 的元素,假设它能通过任意次交换操作抵达的全部的下标位置即为全集 \(U\)。对于任意下标位置 \(j \in U\),都会满足什么性质呢?
这里先给出结论:下标位置 \(i\) 的元素能够抵达的任意下标位置 \(j \in U\) 都满足 \(\text{i % gcd(x, y) == j % gcd(x, y)}\)
设 \(g=gcd(x,y)\),根据裴蜀定理,有:$$ax+by=cg$$
那么下标位置 \(i\) 的元素,就一定可以通过某种移动方案,达到任意一个在全集 \(U\) 的位置。
假设全部元素划分后,共有 \(U_1,U_2,...,U_k\) 共计 \(k\) 个彼此不相交的集合。对于同属于一个集合 \(U\) 的元素,一定是可以随意交换的。为什么同一连通块中的元素可以随意交换?详情见博客:https://zhuanlan.zhihu.com/p/2027293665970721660
那么我们只需要关注在 \(U_1,U_2,...,U_K\) 分别排序以后,是否可以使得原序列变成一个单调序列即可。此题有个额外的性质,就是原序列是一个排列,那么结合分组排序的性质,那么在排序前必须满足 \(i \equiv p[i](mod \text{ } g)\)。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n, x, y;
cin >> n >> x >> y;
int g = gcd(x, y);
bool ok = true;
for (int i = 1; i <= n; i++) {
int v;
cin >> v;
if (v % g != i % g) {
ok = false;
}
}
if (ok) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
return 0;
}
浙公网安备 33010602011771号