链接:http://acm.hdu.edu.cn/showproblem.php?pid=5668
题意:给定n个人的约瑟夫环的出队时间点,求出构造这个出队序列的最小报数k,如果无解输出"Creation August is a SB!"。
分析:看到题解说是模拟得出n个不定方程,然后用中国剩余定理求解。我想这个模拟想了半天,是不是像普通的数学方法求最后一个出队编号一样去做。然后这样想了很久,最后。。这TMn才20,直接手动模拟那个n^2的过程就是了啊!好蠢。然后就a了。。O(n^2)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const int INF=1000000010;
typedef double db;
typedef unsigned long long ull;
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); }
}
int b[25],q[25];
ll a[25],m[25];
ll CRT1(int n,ll *a,ll *m) {
ll M=1,d,y,z,x=0;
for (int i=0;i<n;i++) M*=m[i];
for (int i=0;i<n;i++) {
z=M/m[i];
exgcd(m[i],z,d,d,y);
x=(x+y*z*a[i])%M;
}
return (x+M)%M;
}
ll CRT2(int n,ll *a,ll *m) {
int i,bo=1;
ll n1=m[1],n2,b1=a[1],b2,bb,d,t,k,x,y;
for (i=2;i<=n;i++) {
n2=m[i];b2=a[i];
bb=b2-b1;exgcd(n1,n2,d,x,y);
if (bb%d) {
bo=0;break ;
}
k=bb/d*x;t=abs(n2/d);
k=(k%t+t)%t;b1=b1+n1*k;n1=n1/d*n2;
}
if (!bo) return -1;
if (b1<=0) b1+=n1;
return b1;
}
int main()
{
int i,j,n,t,x,w,tot,pre;
ll ans;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (i=1;i<=n;i++) {
scanf("%d", &x);b[x]=i;
}
w=tot=0;
memset(q,0,sizeof(q));
for (i=1;i<=n;i++) {
for (pre=0,j=1;j<w;j++)
if (!q[j]) pre++;
while (1) {
w=(w%n+n)%n+1;
if (!q[w]) tot++;
if (b[i]==w) break ;
}
a[i]=(ll)tot;m[i]=(ll)(n-i+1);
q[w]=1;tot=0;
}
ans=CRT2(n,a,m);
if (ans==-1) printf("Creation August is a SB!\n");
else printf("%I64d\n", ans);
}
return 0;
}