HDU3430 (置换群循环节+中国剩余定理)

题意:给出n张牌,标号为1-n,然后给出两个序列,序列1表示序列1,2,3,4……,n洗一次牌后到达的,序列2表示目标序列,问初始序列按序列1的洗牌方式洗几次能到达序列2的情况,如果不能到达输出-1。

题解:在初始序列和序列1的变换中找出1能变到那些牌,这些牌构成一个集合,这些集合中的牌必然是能够相互到达的,然后在序列2中也找出这样一个集合,集合中这些元素的相互顺序是要一样的,这就是判断能否达到,然后这样可以列出几个线性同余方程组,用中国剩余定理求解即可(顺便献上中国剩余定理模板)。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
using namespace std;
int n,a[1001],b[1001],vis[1001],c[1001],x[1001],y[1001];
long long exgcd(long long a,long long b,long long &x,long long &y)
{
    if (b==0)
    {
        x=1;
        y=0;
        return a;
    }
    long long gcd=exgcd(b,a%b,x,y);
    long long t=x;
    x=y;
    y=t-a/b*x;
    return gcd;
}
long long china_remain(long long m,int a[],int b[])
{
    //for (int i=1;i<=m;i++)
    //    cout<<a[i]<<" "<<b[i]<<endl;
    long long a1,a2,b1,b2,x,y,flag=0;
    a1=a[0];
    b1=b[0];
    int i;
    for (i=1;i<m;i++)
    {
        a2=a[i];
        b2=b[i];
        long long gcd=exgcd(a1,a2,x,y);
        if ((b2-b1)%gcd)
        {
            flag=1;
            break;
        }
        long long t=a2/gcd;
        x=(x*(b2-b1))/gcd;
        x=(x%t+t)%t;
        b1=a1*x+b1;
        a1=(a1*a2)/gcd;
        b1=(b1%a1+a1)%a1;
    }
    if (flag) return -1;
    return b1;
}
int main()
{
    while (~scanf("%d",&n))
    {
        if (n==0) break;
        int i;
        for (i=1;i<=n;i++) scanf("%d",&a[i]);
        for (i=1;i<=n;i++) scanf("%d",&b[i]);
        memset(vis,0,sizeof(vis));
        int cnt=0;
        bool can=true;
        for (i=1;i<=n;i++) if (!vis[i])
        {
            int flag=i;
            int count=0;
            while (!vis[flag])
            {
                vis[flag]=1;
                c[count++]=flag;
                flag=a[flag];
            }
            int pos=0;
            while (pos<count&&b[i]!=c[pos]) pos++;
            if (pos==count)
            {
                can=false;
                break;
            }
            x[cnt]=count;
            y[cnt++]=pos;
            //cout<<count<<" "<<pos<<endl;
            flag=a[i];
            while (flag!=i)
            {
                if (b[flag]!=c[(++pos)%count])
                {
                    can=false;
                    break;
                }
                flag=a[flag];
            }
            if (!can) break;
        }
        if (!can) puts("-1");
        else printf("%lld
",china_remain(cnt,x,y));
    }
}
原文地址:https://www.cnblogs.com/hnqw1214/p/6602341.html