1. 程式人生 > >HDU 3430 Shuffling(置換群+中國剩餘定理)

HDU 3430 Shuffling(置換群+中國剩餘定理)

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.

 

 

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

    }
}