链接:戳这里
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;
}