HDU5668 Circle 非互质中国剩余定理

时间:2023-03-08 22:13:35

分析:考虑对给定的出圈序列进行一次模拟,对于出圈的人我们显然可以由位置,编号等关系得到一个同余方程

一圈做下来我们就得到了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=;
int n,c[N];
bool vis[N];
LL a[N],m[N];
LL exgcd (LL a, LL b, LL &x, LL &y)
{
if (b == )
{
x = , y = ;
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[], n2, b1 = a[], b2, bb, d, t, k, x, y;
for (int i = ; 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 < ) t = -t;
k = (k % t + t) % t;
b1 = b1 + n1*k;
n1 = n1 / d * n2;
}
if (flag)
return -;
if (b1 == )
b1 = n1;
return b1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=; i<=n; ++i)
{
int x;
scanf("%d",&x);
c[x]=i;
}
memset(vis,,sizeof(vis));
int now=;
for(int i=; i<=n; ++i)
{
int cnt=;
for(int j=now; j<=n+; ++j)
{
if(j==n+)j=;
if(vis[j])continue;
++cnt;
if(j==c[i])break;
}
m[i]=(n-i+);
a[i]=cnt%m[i];
vis[c[i]]=;
if(i==n)break;
for(int j=c[i]; j<=n+; ++j)
{
if(j==n+)j=;
if(vis[j])continue;
now=j;
break;
}
}
LL ans=CRT2(a,m,n);
if(ans==-)printf("Creation August is a SB!\n");
else printf("%I64d\n",ans);
}
return ;
}