Codeforces Harbour.Space Scholarship Contest 2021-2022/1553E Permutation Shift
題目連結:https://codeforces.com/contest/1553/problem/E
題目大意:是否能在轉置\(k\)輪和交換\(m\)次的條件下將\((1,2,3,...,n)\)變成\((a_{1},a_{2},a_{3},...,a_{n})\),\(0\leq k<n,0\leq m\leq \frac{n}{3}\),轉置指元素後移\(k\)位,交換指兩個元素交換位置
題目思路:
先將每個數都減\(1\)
轉置0輪\((0,1,2,3)\)
轉置1輪\((3,0,1,2)\)
轉置2輪\((2,3,0,1)\)
轉置3輪\((1,2,3,0)\)
不難發現轉置k輪實際上就是\(p[i] = i-k(mod \ n)\)
對於每一個轉置我們可以求出對a序列來說不動點的個數
a序列為\((1,2,0,3)\)
轉置0輪\((0,1,2,3)\),不動點數\(cnt[0] = 1\)
轉置1輪\((3,0,1,2)\),不動點數\(cnt[1] = 0\)
轉置2輪\((2,3,0,1)\),不動點數\(cnt[2] = 1\)
轉置3輪\((1,2,3,0)\),不動點數\(cnt[3] = 2\)
不動點即\(a[i] =p[i] = i-k(mod \ n)\),得 \(k = i-a[i] (mod \ n)\),因\(++cnt[k]\)即可
剩下都是需要移動的點,交換\(m\)次最多可導致\(2m\)個元素交換,因此可以判斷如果\(cnt[k]+2m<n\)
因為\(m\leq \frac{n}{3}\),最多可以交換\(\frac{2n}{3}\)個元素,剩下\(\frac{n}{3}\)是不動點的個數,又因為\(\sum cnt[k] = n\),最多隻有3個\(k\)是滿足條件的,直接暴力即可
暴力求出環數\(num\),需要移動的點即為\(n-num\)
AC程式碼:
#include <unordered_map> #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <string> #include <stack> #include <deque> #include <queue> #include <cmath> #include <map> #include <set> using namespace std; typedef pair<int, int> PII; typedef pair<double, int> PDI; //typedef __int128 int128; typedef long long ll; typedef unsigned long long ull; const int INF = 0x3f3f3f3f; const int N = 3e5 + 10, M = 4e7 + 10; const int base = 1e9; const int P = 131; const int mod = 1e9 + 7; const double eps = 1e-9; const double PI = acos(-1.0); int a[N], cnt[N], ans[5]; int pos; bool vis[N]; int main() { int T; scanf("%d", &T); while (T--) { pos = 0; int n, m; scanf("%d%d", &n, &m); for (int i = 0; i < n; ++i) { scanf("%d", &a[i]); --a[i]; ++cnt[(i - a[i] + n) % n]; } for (int k = 0; k < n; ++k) { if (cnt[k] + 2 * m < n) continue; for (int i = 0; i < n; ++i) vis[i] = false; int num = 0; for (int i = 0; i < n; ++i) { if (vis[i]) continue; for (int j = i; !vis[j]; j = (a[j] + k) % n) vis[j] = true; ++num; } if (n - num <= m) ans[++pos] = k; } printf("%d ", pos); for (int i = 1; i <= pos; ++i) printf("%d ", ans[i]); printf("\n"); } return 0; }