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; }