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;
}
posted @ 2020-07-25 14:49  GK0328  阅读(108)  评论(0编辑  收藏  举报