HDU 3430 Shuffling(置换群+中国剩余定理)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37025443/article/details/84171058

Shuffling

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 548    Accepted Submission(s): 266


 

Problem Description

A casino owns an expensive card shuffling machine which may shuffle up to 520 cards at a time (there are 52 cards in each deck). For convenience, we will simply label the cards 1, 2, 3, ..., N where N is the total number of cards, and copies of the same card (e.g. Ace of Spades) from different decks are considered different. Unfortunately, the card shuffling machine is defective, and it always shuffles the cards the same way. The company that produces these machines is out of business because of the economic downturn. There is no one who can fix the machine, and a new machine is too expensive.

Being a brilliant employee of the casino, you realized that all is not lost. You can shuffle the cards differently simply by using the machine zero or more times. For example, suppose that the machine shuffles the cards 1, 2, 3, 4 into the order 2, 3, 4, 1. If you put the cards into the machine, take the shuffled cards out and insert them into the machine again (without changing the order), you will get the order 3, 4, 1, 2. That way, it is possible to shuffle the cards in many different ways even though it may take longer. But this is not a significant issue since decks do not have to be reshuffled often, and used decks can be shuffled while other decks are being used to avoid any waiting time.

Unfortunately, not all shufflings can be produced in this way in general, and you wish to know if this procedure "stack the decks" in a favorable way for the casino or the player. As a first step, you wish to know which shufflings are possible to produce, and how many times you need to use the machine on the deck in order to produce the shuffling.

 

Input

The input for each case consists of three lines. The first line consists of a single integer N indicating the number of cards to shuffle. The number of cards is a positive integer up to 520. The second line consists of the integers 1, 2, ..., N listed in some order and separated by a space. The list gives the order of the shuffling performed by the machine when the input cards are ordered 1, 2, ..., N. The third line is in the same format as the second line, and gives the shuffling we wish to obtain. The end of input is indicated by a line in which N = 0.

 

Output

For each case, print the smallest number of times (zero or more) you need to pass the deck through the machine to produce the desired shuffling. If it is not possible, print -1. The output for each case should be in a single line. You may assume that the answer will always fit in a 32-bit signed integer.

扫描二维码关注公众号,回复: 4129208 查看本文章

 

Sample Input

 

4

2 3 4 1

3 4 1 2

4

2 3 4 1

1 3 2 4

10

2 1 3 5 6 7 8 9 10 4

1 2 3 9 10 4 5 6 7 8 0

 

Sample Output

 

2

-1

12

 题意:

给你两个序列,初始序列是1.....n,序列1是第一次置换的结果,序列2是你期望得到的结果。

问你从初始序列通过该置换最少需要多少次变成序列2

解析:

首先可以把置换转换成几个不相交的轮换,各个轮换之间相互独立,互不影响

所以每次得到一个轮换,我们就需要在序列2中找对应的轮换。看看这两个轮换是不是循环同构

这道题关键的一点就是怎么判断这两个轮换是否循环同构

那么这里就需要搞清楚一点,每一个轮换在序列中的位置是固定的。[1,3,4,5]这个轮换永远是在序列的1 3 4 5之间循环

并且置换的a[i]就是表示i所在的轮换中,下一个的位置,相当于一条边i-->a[i]

那么我们就可以从一个轮换的起点开始,并且找到序列2中对应的数在轮换中的位置

譬如[1,3,4,5]的1的位置初始位置是1,那么我们看b[1]是什么数,这个数一定是1,3,4,5中的一个,否则就输出-1

如果b[1]=4,那么我们就把起点移到轮换的第三个数4,然后就可以开始比较了,轮换中循环变量+1,b[]中i=a[i]来递增

当时做的时候,脑子有点混,被置换、轮换绕晕了....

最后得到每一个轮换的结果 x%轮换的长度=轮换的余数,譬如上面就是 x%4=4-3+1

那么我们最后得到一个同余方程,用中国剩余定理解一下就可以了

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
typedef long long lli;
using namespace std;
const int MAXN = 600;
int vis[MAXN];
int a[MAXN],b[MAXN];
int siz[MAXN];
int yu[MAXN];
int c[MAXN];



lli Extend(lli a,lli b,lli &x,lli &y)

{

    lli d;

    if(b==0)

    {

        x=1;

        y=0;

        return a;   //a是a,b的最大公约数

    }

    d=Extend(b,a%b,y,x);

    y-=(a/b)*x;     //x1=y2; y1=x2-(a/b)*y2;

    return d;

}



lli   China(int k,int w[],int r[]) //w除数,r余数


{

    lli w1=w[1];

    lli r1=r[1];

    lli w2,r2,c,d,x,y,s;

    for(int i=2;i<=k;i++)

    {

        w2=w[i];

        r2=r[i];

        c=r2-r1;

        d=Extend(w1,w2,x,y);

        if(c%d)

        {

            //flag=1;

            return -1;

        }

        else

        {

            x=x*c/d;

            s=w2/d;

            x=(x%s+s)%s;

            r1=x*w1+r1;

            w1=w1*w2/d;

        }

    }

    d=Extend(1,w1,x,y);

    if(r1%d)

    {

        //flag=1;

        return -1;

    }

    else

    {

        x=x*r1/d;

        s=w1/d;

        x=(x%s+s)%s;

        if(x==0)

        {

            //flag=1;

            return 0;

        }

        else

        {

            return x;

        }



    }

}

int main()
{
    int n;
    while(scanf("%d",&n),n)
    {
        for(int i=1;i<=n;i++)   //输入是置换一次的结果,a是置换
        {
            int tmp;
            scanf("%d",&tmp);
            a[tmp]=i;
            vis[i]=0;
        }


        for(int i=1;i<=n;i++)
        {
            scanf("%d",&b[i]);
        }
        int flag=1;
        int cnt=1;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]) continue;
            int cmm=0;
            int u=i;
            while(!vis[u])
            {
                c[cmm++]=u;
                vis[u]=1;
                u=a[u];
            }

            int pos=0;
            while(pos<cmm&&b[i]!=c[pos]) pos++;  //找到b中这个轮换是以哪一个开头
            if(pos==cmm){flag=0;break;}
            siz[cnt]=cmm;yu[cnt]=(cmm-pos)%cmm;  //如果把输入当作置换那yu[cnt]=pos
            cnt++;
            //检验b中这个轮换是不是跟c一模一样
            //a是置换,只要按照这个遍历b数组就可以了
            u=a[i];
            while(u!=i)
            {
                if(b[u]!=c[(++pos)%cmm]) {flag=0;break;}
                u=a[u];
            }

        }
        if(!flag) printf("-1\n");
        else
        {
            printf("%lld\n",China(cnt-1,siz,yu));
        }

    }
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/84171058