标签:
分析:考虑对给定的出圈序列进行一次模拟,对于出圈的人我们显然可以由位置,编号等关系得到一个同余方程
一圈做下来我们就得到了n个同余方程 对每个方程用扩展欧几里得求解,最后找到最小可行解就是答案.
当然不要忘了判无解的情况. 有非常多选手似乎都是一眼标算然后写挂了,对此表示很遗憾,但是此题确实是比较容易写挂的...
注:中国剩余定理 解模线性方程组的时候
有两种情况 1:一种是模数是两辆互质的,这样的题可以用LRJ白书上的模板,俗称CRT1
2:模数存在不互质的,这样的需要用合并方程的做法,俗称CRT2
CRT2可以在这位神犇的博客里找到(我就是看的这个,表示涨姿势)http://972169909-qq-com.iteye.com/blog/1266328
CRT1自行参照LRJ白书
AC代码:
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> using namespace std; typedef long long LL; const int N=21; int n,c[N]; bool vis[N]; LL a[N],m[N]; LL exgcd (LL a, LL b, LL &x, LL &y) { if (b == 0) { x = 1, y = 0; return a; } LL d=exgcd(b,a%b,y,x); y-=a/b*x; return d; } LL CRT2 (LL a[], LL m[], int num) { bool flag = false; LL n1 = m[1], n2, b1 = a[1], b2, bb, d, t, k, x, y; for (int i = 2; i <= num; i++) { n2 = m[i], b2 = a[i]; bb = b2 - b1; d = exgcd (n1, n2, x, y); if (bb % d) { flag = true; break; } k = bb / d * x; t = n2 / d; if (t < 0) t = -t; k = (k % t + t) % t; b1 = b1 + n1*k; n1 = n1 / d * n2; } if (flag) return -1; if (b1 == 0) b1 = n1; return b1; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1; i<=n; ++i) { int x; scanf("%d",&x); c[x]=i; } memset(vis,0,sizeof(vis)); int now=1; for(int i=1; i<=n; ++i) { int cnt=0; for(int j=now; j<=n+1; ++j) { if(j==n+1)j=1; if(vis[j])continue; ++cnt; if(j==c[i])break; } m[i]=(n-i+1); a[i]=cnt%m[i]; vis[c[i]]=1; if(i==n)break; for(int j=c[i]; j<=n+1; ++j) { if(j==n+1)j=1; if(vis[j])continue; now=j; break; } } LL ans=CRT2(a,m,n); if(ans==-1)printf("Creation August is a SB!\n"); else printf("%I64d\n",ans); } return 0; }
标签:
原文地址:http://www.cnblogs.com/shuguangzw/p/5406111.html