Aizu2970 Permutation Sort
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2970
扩展中国剩余定理(EXCRT)
根据容斥原理,每个数最多变换\(n\)次就会进入循环,我们把循环记录下来
例如样例\(1\):
\[P:2\quad 3\quad 1\quad 4\quad 5\quad 6\\
Q:3\quad 1\quad 2\quad 5\quad 4\quad 6\\
第1个位置:2 \rightarrow 1 \rightarrow 3 \rightarrow 2\\
第2个位置:3 \rightarrow 2 \rightarrow 1 \rightarrow 3\\
第3个位置:1 \rightarrow 3 \rightarrow 2 \rightarrow 1\\
第4个位置:4 \rightarrow 5 \rightarrow 4\\
第5个位置:5 \rightarrow 4 \rightarrow 5\\
第6个位置:6 \rightarrow 6\\
最终,p[i]必须转化为i(如果不能,则无解,忘记判调了好久)\\
用a_{i}表示循环长度,b_{i}表示在一个循环中,i属于第几位(从0开始)\\
设做x步满足题意,则:\\
\begin{cases}
x \equiv a_{1} (\mod b_{1})\\
x \equiv a_{2} (\mod b_{2})\\
\cdots \\
x \equiv a_{n} (\mod b_{n})\\
\end{cases} \\
好眼熟啊\\
EXCRT,Over了
\]
\(C++ Code:\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll __int128
#define int __int128
#define N 405
using namespace std;
int n,a[N],b[N],g[N][N],y[N];
bool vis[N];
ll B,W;
template<typename T>
inline void read(T &x)
{
x=0;
T otz=1,ch=getchar();
while (!isdigit(ch)&&ch!='-')
ch=getchar();
if(ch=='-')
{
otz=-1;
ch=getchar();
}
while (isdigit(ch))
{
x=x*10+ch-'0';
ch=getchar();
}
x*=otz;
}
template<typename T>
inline void write(T x)
{
if (x<0)
{
x=-x;
putchar('-');
}
if (x>=10)
write(x/10);
putchar(x%10+'0');
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if (!b)
{
x=1;
y=0;
return a;
}
ll z=exgcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-a/b*y;
return z;
}
ll gcd(ll x,ll y)
{
if (!y)
return x;
return gcd(y,x%y);
}
void EXCRT()
{
ll a1,n1,a2,n2,k1,k2,x,Y,d,x1,y1,G;
a1=y[1];
n1=g[1][0];
for (int i=2;i<=n;i++)
{
a2=y[i];
n2=g[i][0];
d=a2-a1;
G=exgcd(n1,n2,x1,y1);
if (d%G)
{
printf("-1\n");
exit(0);
}
k1=x1*d/G;
k1=(k1%(n2/G)+n2/G)%(n2/G);
x=a1+k1*n1;
a1=x;
n1=n1*n2/G;
}
write(a1),putchar('\n');
}
signed main()
{
read(n);
for (int i=1;i<=n;i++)
read(a[i]);
for (int i=1;i<=n;i++)
read(b[i]);
for (int i=1;i<=n;i++)
y[i]=-1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
vis[j]=false;
int now=a[i];
for (;;)
{
if (vis[now])
break;
vis[now]=true;
g[i][++g[i][0]]=now;
if (now==i)
y[i]=g[i][0]-1;
now=b[now];
}
}
for (int i=1;i<=n;i++)
if (y[i]==-1)
{
printf("-1\n");
return 0;
}
EXCRT();
return 0;
}