http://acm.hdu.edu.cn/showproblem.php?pid=5668
这题的话,假设每次报x个,那么可以模拟一遍,
假设第i个出局的是a[i],那么从第i-1个出局的人后,重新报数到他假设经过了p个人,
那么自然x = k(n-i)+p(0<= i < n)
即x = p (mod n-i)
然后显然可以得到n个这样的方程,于是就是中国剩余定理了。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <string> #define LL long long using namespace std; int n, s[25]; bool vis[25]; LL rest[25], mmod[25]; LL gcd(LL a, LL b) { LL r; while (b != 0) { r = b; b = a%b; a = r; } return a; } LL lcm(LL a, LL b) { return a/gcd(a, b)*b; } //EXGCD //求解方程ax+by=d,即ax=d mod(b) //扩展可求逆元 //O(logn) void exgcd(LL a, LL b, LL &x, LL &y, LL &d) { if (b == 0) { x = 1; y = 0; d = a; } else { exgcd(b, a%b, y, x, d); y -= a/b*x; } } //中国剩余定理(非互质) //其中a为除数数组,n为模数数组 LL inv(LL a, LL n) { LL x, y, d; exgcd(a, n, x, y, d); if (d != 1) return -1; return (x%n + n) % n; } bool Merge(LL a1, LL n1, LL a2, LL n2, LL &aa, LL &nn) { LL d = gcd(n1, n2); LL c = a2 - a1; if (c % d) return false; //(n1/d)*k1 = (c/d)(mod(n2/d)) c /= d; n1 /= d; n2 /= d; //k1 = (c/d)*(n1/d)^(-1)(mod(n2/d)) c *= inv(n1, n2); c %= n2;//k1 c *= n1 * d;//a = n1*k1+a1 c += a1; nn = n1*n2*d; aa = c; return true; } LL CRT(int len, LL *a, LL *n) { LL a1 = a[0], n1 = n[0]; LL a2, n2; for (int i = 1; i < len; i++) { LL aa, nn; a2 = a[i], n2 = n[i]; if (!Merge(a1, n1, a2, n2, aa, nn)) return -1; a1 = aa; n1 = nn; } return (a1%n1 + n1) % n1; } void work() { LL ans, tmp = 1; memset(vis, false, sizeof(vis)); int now = 0, step, t = 0; for (int i = 0; i < n; ++i) { step = 0; for (int j = t%n; j < n; j = (j+1)%n) { if (vis[j]) continue; step++; if (j == s[now]) { now++; vis[j] = true; rest[i] = step%(n-i); mmod[i] = n-i; tmp = lcm(tmp, n-i); t = j; break; } } } ans = CRT(n, rest, mmod); if (ans == -1) printf("Creation August is a SB!\n"); else { ans = (ans%tmp+tmp)%tmp; if (ans == 0) ans = tmp; cout << ans << endl; } } int main() { //freopen("test.in", "r", stdin); int T, u; scanf("%d", &T); for (int times = 1; times <= T; ++times) { scanf("%d", &n); for (int i = 0; i < n; ++i) { scanf("%d", &u); s[u-1] = i; } work(); } return 0; }
时间: 2024-10-14 12:12:32