POJ 1271 CARDS 置換/迴圈節/置換群開方

來源:互聯網
上載者:User

題意:直接引用潘震皓的論文《置換群快速冪運算》。

[問題描述]

剴剴和凡凡有N張牌(依次標號為1,2,……,N)和一台洗牌機。假設N是奇數。洗牌機的功能是進行如下的操作:對所有位置I(1≤I≤N),如果位置I上的牌是J,而且位置J上的牌是K,那麼通過洗牌機後位置I上的牌將是K。

剴剴首先寫下一個1~N的排列ai,在位置ai處放上數值ai+1的牌,得到的順序x1,x2, ..., xN作為初始順序。他把這種順序排列的牌放入洗牌機洗牌S次,得到牌的順序為p1,p2, ..., pN。現在,剴剴把牌的最後順序和洗牌次數告訴凡凡,要凡凡猜出牌的最初順序x1,
x2,..., xN。

[輸入]

第一行為整數N和S。1≤N≤1000,1≤S≤1000。第二行為牌的最終順序p1,p2, ..., pN。

[輸出]

為一行,即牌的最初順序x1,x2, ..., xN。


註:在置換群中有一個定理:設,(T為一置換,e為單位置換(映射函數為的置換)),那麼k的最小正整數解是T的拆分的所有迴圈長度的最小公倍數。或者有個更一般的結論:設,(T為一迴圈,e為單位置換),那麼k的最小正整數解為T的長度。

[演算法分析]

很顯然,這題的一副撲克牌就是一個置換,而每一次洗牌就是這個置換的平方運算。由於牌的數量是奇數,並且一開始是一個大迴圈,所以做平方運算時候不會分裂。所以,在任意時間,牌的順序所表示的置換一定是一個大迴圈。

那麼根據文章開頭提到的定理:設,(T為一迴圈,e為單位置換),那麼k的最小正整數解為T的長度。

可以知道,這個迴圈的n次方是單位迴圈,換句話說,如果k mod n=1,那麼這個迴圈的k次方,就是它本身。我們知道,每一次洗牌是一次簡單的平方運算,洗x次就是原迴圈的2x次方。

因為n是奇數,2x mod n=1一定有一個<n的整數解,假設這個解是a;那也就是說,一幅牌,洗a次,就會回到原來的順序。使用最終順序不停地洗,直到回到原始順序,求出迴圈節長度a以後,再單純地向前類比a-s次,就可以得到原始順序了。

上面的演算法是出題方給出的標準演算法。顯然,時間複雜度為O(n2+logs)。

換一個方向:給定了結果和s以後,可以簡單地將這個目標置換用3.1節的方法開方s次得到結果。時間複雜度為O(n*s)。

或者可以更簡單地,算出2s,將目標置換直接開2s次方。這裡有一個技巧,因為在開方時只需要在迴圈中前進2s次,所以我們只關心(2s) mod n,也就免去了大數位運算。所以,計算2s需要O(logs),而開方需要O(n)。整個時間複雜度為O(n+logs)。


方法一:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 1100int p[MAXN];bool flag[MAXN];void permute ( int n ) //類比置換{    int now, i, tmp[MAXN];    memset(flag,0,sizeof(flag));    for ( i = 1; i <= n; i++ )    {        if ( flag[i] ) continue;        now = i;        while ( flag[now] == 0 )        {            flag[now] = 1;            tmp[now] = p[p[now]];            now = p[p[now]];        }    }    for ( i = 1; i <= n; i++ ) p[i] = tmp[i];}int mod_exp ( int a, int b, int n ){    int ret = 1;    a = a % n;    while ( b >= 1 )    {        if ( b & 1 )            ret = ret * a % n;        a = a * a % n;        b >>= 1;    }    return ret;}int main(){    int n, s, a, i;    scanf("%d%d",&n,&s);    for ( i = 1; i <= n; i++ )        scanf("%d",&p[i]);    for ( a = 1; mod_exp(2,a,n) != 1; a++ );    s = s % a;    for ( i = 1; i <= a - s; i++ )        permute ( n );    for ( i = 1; i <= n; i++ )        printf("%d\n",p[i]);    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.