链接:戳这里
Circle
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
\ \ \ \ Fye对约瑟夫游戏十分着迷.
\ \ \ \ 她找到了n个同学,把他们围成一个圈,让他们做约瑟夫游戏,然后她得到了一个同学们出圈的编号序列.游戏是这样进行的:以同学1为起点,开始计数,计数到第k个同学,该同学出圈.出圈的同学将不参与之后的计数.
\ \ \ \ 如今Fye找到了你,她想让你告诉他满足已知出圈序列的最小的k,如果你回答不上来,她就会很生气然后把你吊打一顿.
输入描述
\ \ \ \ 第一行一个数T,为测试数据组数.
\ \ \ \ 对每组测试数据,第一行一个数n.
\ \ \ \ 第二行nn个数,为同学的出圈序列(第ai个出圈的人,编号为i).
\ \ \ \ 输入数据必须是一个11到nn的合法排列.
\ \ \ \ 1≤T≤10,2≤N≤20.
输出描述
\ \ \ \ 对于每组测试数据,若存在合法的k,输出一个正整数,为合法的最小k,否则输出”Creation August is a SB!“.
输入样例
1
7
7 6 5 4 3 2 1
输出样例
420
思路:
约瑟夫环问题的一般步骤是数k步 然后当前的i出列
已知每一次出环的位置,那么模拟这个过程
(a[i-1]+k) %mi = ai % mi 其中ai为->在环内数ai个还在环内的人 比如当前是123 上 2这个位置出环,那么我只需要2个没有标记的人,数完之后所在的位置 mi为环内还存活的人数
1:(0+k)%n=a1%n
2:(a1+k)%(n-1)=a2%(n-1)
....
3:(a[i-1]+k)%1=an%1
ai的话需要模拟求得,其实也就是数出cnt个人之后第bi个人出环 (出环的顺序已知
显然是中国剩余定理 前提是mi不互质
具体的中国剩余定理解析戳下面
http://yzmduncan.iteye.com/blog/1323599
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<vector> #include <ctime> #include<queue> #include<set> #include<map> #include<stack> #include<iomanip> #include<cmath> #define mst(ss,b) memset((ss),(b),sizeof(ss)) #define maxn 0x3f3f3f3f #define MAX 1000100 ///#pragma comment(linker, "/STACK:102400000,102400000") typedef long long ll; typedef unsigned long long ull; #define INF (1ll<<60)-1 using namespace std; void exgcd(ll a,ll b,ll &d,ll &x,ll &y){ if(!b){ d=a; x=1; y=0; } else { exgcd(b,a%b,d,y,x); y-=x*(a/b); } } ll gcd(ll a,ll b){ return b==0 ? a : gcd(b,a%b); } /* a*x = 1%m 逆元 */ ll inv(ll a,ll m){ ll d,x,y; exgcd(a,m,d,x,y); if(d!=1) return -1; return (x%m+m)%m; } bool Merge(ll a1,ll m1,ll a2,ll m2,ll &a3,ll &m3){ ll d=gcd(m1,m2); ll c=a2-a1; if(c%d!=0) return false; c=(c%m2+m2)%m2; c/=d; m1/=d; m2/=d; c*=inv(m1,m2); c%=m2; c*=m1*d; c+=a1; m3=m1*m2*d; a3=(c%m3+m3)%m3; return true; } ll china_Reminder(int n,ll *a,ll *m){ ll a1=a[1],m1=m[1]; ll a2,m2; for(int i=2;i<=n;i++){ ll aa,mm; a2=a[i]; m2=m[i]; if(!Merge(a1,m1,a2,m2,aa,mm)) return -1; a1=aa; m1=mm; } ll t=(a1%m1+m1)%m1; if(t==0) return m1; return t; } ll a[22],b[22]; ll m[22]; int n; int vis[22]; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) m[i]=(ll)n-i+1LL; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); b[x]=(ll)i; } int w=0,cnt=0; mst(vis,0); for(int i=1;i<=n;i++){ while(1){ w=(w%n+n)%n+1; if(!vis[w]) cnt++; if(w==b[i]) break; } a[i]=(ll)cnt%m[i]; vis[w]=1; cnt=0; } ll ans=china_Reminder(n,a,m); if(ans==-1) printf("Creation August is a SB!\n"); else printf("%I64d\n",ans); } return 0; }