中国剩余定理。
可以手动模拟一下每一次开始的人的编号和结束的人的编号。
每次删掉一个人,对剩下的人重新编号。
这样一次模拟下来,可以得到n个方程
形如:(u[i]+k)%(n-i+1)=v[i]
化简一下就是:k%(n-i+1)=v[i]-u[i]%(n-i+1)
接下来就是求解最小的k,满足所有式子
中国剩余定理板子一套就AC了......
#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> using namespace std; typedef long long LL; const int maxn = 30; int n, T; int s[maxn], flag[maxn], tmp[maxn]; int u[30], v[30]; LL a[maxn], b[maxn]; void ls() { int cnt = 1; for (int i = 1; i <= n; i++) { if (flag[i] == 0) tmp[cnt++] = i; } } int Find(int a) { for (int i = a; i <= n; i++) if (flag[i] == 0) return i; for (int i = 1; i <= a; i++) if (flag[i] == 0) return i; } int f2(int a) { for (int i = 1;; i++) if (tmp[i] == a) return i; } void egcd(LL a, LL b, LL&d, LL&x, LL&y) { if (!b) { d = a, x = 1, y = 0; } else { egcd(b, a%b, d, y, x); y -= x*(a / b); } } LL lmes() { LL M = a[1], R = b[1], x, y, d; for (int i = 2; i <= n; i++) { egcd(M, a[i], d, x, y); if ((b[i] - R) % d) return -1; x = (b[i] - R) / d*x % (a[i] / d); R += x*M; M = M / d*a[i]; R %= M; } return (R + M) % M ? (R + M) % M : M; } void exgcd(LL a, LL b, LL &d, LL &x, LL &y) { if (b == 0) d = a, x = 1, y = 0; else { exgcd(b, a%b, d, y, x); y -= x * (a / b); } } LL china(LL n, LL m[], LL a[]) { LL aa = a[0]; LL mm = m[0]; for (int i = 0; i<n; i++) { LL sub = (a[i] - aa); LL d, x, y; exgcd(mm, m[i], d, x, y); if (sub % d) return -1; LL new_m = m[i] / d; new_m = (sub / d*x%new_m + new_m) % new_m; aa = mm*new_m + aa; mm = mm*m[i] / d; } aa = (aa + mm) % mm; return aa ? aa : mm; } int main() { scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; i++) { int ai; scanf("%d", &ai); s[ai] = i; } memset(flag, 0, sizeof flag); u[1] = 0, v[1] = s[1]; if (v[1] == n) v[1] = 0; flag[s[1]] = 1; for (int i = 2; i <= n; i++) { int st, en; ls(); st = Find(s[i - 1]), st = f2(st), st = st - 1; if (st == -1) st = n - i; en = f2(s[i]), u[i] = st; v[i] = en; if (v[i] == n - i+1) v[i] = 0; flag[s[i]] = 1; } /* for (int i = 1; i <= n; i++) printf("%d %d\n", u[i], v[i]); */ //接下来就是求解最小的k,满足所有式子 //k%(n-i+1)=v[i]-u[i]%(n-i+1) for (int i = 1; i <= n; i++) { a[i] = (LL)(n - i + 1); b[i] = (LL)(v[i] - u[i] % (n - i + 1)); } LL k = china(n, a + 1, b + 1); if (k == -1) printf("Creation August is a SB!\n"); else printf("%lld\n", k); } return 0; }
时间: 2024-10-29 01:14:48