BZOJ 2976: [Poi2002]出圈游戏 Excrt+set
人数很少,可以直接用 $set$ 来模拟人的情况.
然后就能得到若干个方程,用 $excrt$ 进行合并即可.
#include <set>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 23
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
set<int>S;
set<int>::iterator it;
int edges,size,n;
int ou[N],A[N];
ll arr[N],brr[N];
bool cmp(int i,int j)
{
return ou[i]<ou[j];
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1,y=0;
return a;
}
ll gcd=exgcd(b,a%b,x,y),tmp=x;
x=y,y=tmp-a/b*y;
return gcd;
}
ll Excrt()
{
int i,j;
ll ans=arr[1],M=brr[1];
for(i=2;i<=n;++i)
{
ll a=M,b=brr[i],c=arr[i]-ans,x,y;
ll gcd=exgcd(a,b,x,y);
if(c%gcd)
{
return -1;
}
b=abs(b/gcd);
x=x*(c/gcd),x=(x%b+b)%b;
ans=ans+M*x;
M*=brr[i]/__gcd(brr[i],M);
ans=(ans%M+M)%M;
}
return ans;
}
int main()
{
int i,j;
// setIO("input");
scanf("%d",&n);
for(i=1;i<=n;++i)
{
scanf("%d",&ou[i]),A[i]=i;
}
for(i=1;i<=n;++i) S.insert(i);
sort(A+1,A+1+n,cmp);
arr[1]=A[1]-1;
brr[1]=n;
for(i=2;i<=n;++i)
{
int cnt=0,flag=0;
for(it=S.begin();;it++)
{
if((*it)==A[i-1]) break;
}
cnt=-1;
for(it++;it!=S.end();it++)
{
++cnt;
if((*it)==A[i])
{
flag=1;
break;
}
}
if(!flag)
{
for(it=S.begin();it!=S.end();it++)
{
++cnt;
if((*it)==A[i])
{
break;
}
}
}
S.erase(A[i-1]);
brr[i]=brr[i-1]-1, arr[i]=cnt;
}
ll p=Excrt();
if(p!=-1) printf("%lld\n",p+1);
else printf("NIE\n");
return 0;
}

浙公网安备 33010602011771号