1. 程式人生 > >[bzoj1004] [HNOI2008] Cards

[bzoj1004] [HNOI2008] Cards

png http scanf b+ 序列 排列 spa 。。 name

Description

小春現在很清閑,面對書桌上的 \(N\) 張牌,他決定給每張染色,目前小春只有 \(3\) 種顏色:紅色,藍色,綠色.他詢問 \(Sun\) 有多少種染色方案, \(Sun\) 很快就給出了答案.進一步,小春要求染出 \(Sr\) 張紅色, \(Sb\) 張藍色, \(Sg\) 張絕色.他又詢問有多少種方案, \(Sun\) 想了一下,又給出了正確答案. 最後小春發明了 \(M\) 種不同的洗牌法,這裏他又問 \(Sun\) 有多少種不同的染色方案.兩種染色方法相同當且僅當其中一種可以通過任意的洗牌法(即可以使用多種洗牌法,而每種方法可以使用多次)洗成另一種. \(Sun\)

發現這個問題有點難度,決定交給你,答案可能很大,只要求出答案除以 \(P\) 的余數( \(P\) 為質數).

Input

第一行輸入 \(5\) 個整數:\(Sr\),\(Sb\),\(Sg\),\(m\),\(p\)\((m<=60,m+1<p<100)\)\(n=Sr+Sb+Sg\)
接下來 \(m\) 行,每行描述一種洗牌法,每行有 \(n\) 個用空格隔開的整數 \(X1X2...Xn\),恰為 \(1\)\(n\) 的一個排列,表示使用這種洗牌法,第 \(i\) 位變為原來的 \(Xi\) 位的牌。輸入數據保證任意多次洗牌都可用這 \(m\) 種洗牌法中的一種代替,且對每種洗牌法,都存在一種洗牌法使得能回到原狀態。

Output

不同染法除以 \(P\) 的余數

Sample Input

1 1 1 2 7

2 3 1

3 1 2

Sample Output

2

HINT

\(2\) 種本質上不同的染色法 \(RGB\)\(RBG\),使用洗牌法 \(231\) 一次可得 \(GBR\)\(BGR\) ,使用洗牌法 \(312\) 一次 可得 \(BRG\)\(GRB\)
\(100%\) 數據滿足 \(Max{Sr,Sb,Sg} \leq 20\)


想法

該題為 \(Burnside\) 引理的典型應用題。

預備知識

置換:在集合論中,一個集合的置換是從該集合映至自身的雙射。
它是一種運算
置換群

:n元對稱群的任意一個子群,都叫做一個n元置換群,簡稱置換群。
簡單來說,就是若幹置換組成的集合,且滿足“群”的特點,即:
\(i)\) 封閉性:置換群 \(G\) 中任意兩個置換結合形成的置換在 \(G\)
\(ii)\) 結合性:(\(a\) 結合 \(b\)) 結合 \(c\) \(=\) \(a\) 結合 (\(b\) 結合 \(c\)
\(iii)\) 單位元: \(G\) 中存在置換 \(e\) 滿足 \(e\)\(G\) 中任意置換 \(a\) 結合,結果為 \(a\) (即 \(e\) 為單位元)
\(iiii)\) 逆元: 對 \(G\) 中任意置換 \(a\)\(G\) 中都存在置換 \(b\) 使 \(a\)\(b\) 結合後結果為 \(e\)
等價類 :某個序列 \(A\) 經過 \(G\) 中的某個置換變成 \(B\), 則 \(A\)\(B\) 屬於同一等價類
不動點: 若一個序列 \(A\) 經過置換 \(a\) 後仍為 \(A\) , 則稱 \(A\) 為置換 \(a\) 的不動點

Burnside引理

設置換群 \(G\) 為等價關系集合,\(C(f)\) 表示置換 \(f\) 的不動點個數。
則等價類個數 \(L=\frac{\sum{C(f)}}{|G|}\)
證明不會。。。先記住就好

計算不動點個數

其實每個置換可以寫成若幹個循環乘積形式
如置換 \(2 4 5 1 3\) 中,其實只有 \(1,2,4\) 互換位置, \(3,5\) 互換位置,故可以寫成:
\((1,2,4) \cdot (3,5)\)
技術分享圖片

染色問題中, 若要經過一次置換後仍不變,則\(1,2,4\) 必須同色, \(3,5\) 必須同色,而這兩者之間顏色互不幹擾。
故這個置換的不動點個數為 \(顏色數 ^ 2\)
\(\Rightarrow\) 設顏色數為 \(m\) , 某一個置換有 \(x\) 個循環節,則該置換的不動點個數為 \(m^x\)

Polya定理

其實就是上面的 \(Burnside\) 引理與 計算不動點個數的結合,專門針對染色問題。
\(G\)\(n\) 個對象的一個置換群, 用 \(m\) 種顏色染圖這 \(n\) 個對象,則不同的染色方案數為:
\(L=\frac{\sum{m^{C(f)}}}{|G|}\)
註意在這裏面 \(C(f)\) 表示置換 \(f\) 的循環節數。

小例題

有一個圓形項鏈,上面有 \(n\) 個珠子,這 \(n\) 個珠子由 \(m\) 中顏色組成。經過旋轉後(不是翻轉!)相同的項鏈為相同的項鏈,請問一共有多少不同的項鏈?
解法:
本題中的置換群為
\[ \left\{ \begin{matrix} 1 & 2 & 3 & … & n\ 2 & 3 & … & n & 1 \ … & … & … & … & …\ n & 1 & 2 & 3 & … \end{matrix} \right\} \]
我們管這個置換群中的置換形象地叫做“轉圈圈置換”
則置換群中第 \(i\) 個置換(順序見上),它的循環節數為 \(gcd(i,n)\)
應用 \(Polya\) 定理既可做出來。

本題解法!!!

題中所說的洗牌法基本滿足置換群性質,只要加上單位元就是真正的置換群了!
為了套用定理,我們要考慮如何計算不動點個數。
如果沒有對 \(RGB\) 數量的限制,那暴力找循環就可以了然後套 \(Polya\) 定理就行了。
但有限制咋辦呢?
——還是暴力找循環,記下每個環的大小。由於每個環上點必須是同一顏色,問題轉化為把環扔進3個大小有限制的背包中,求放法。
\(DP\) 就好啦。


代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
 
using namespace std;
 
const int N = 65;
typedef long long ll;
 
int sr,sb,sg,m,n,P;
int cg[N][N];
 
int Pow_mod(int x,int y){
    int ret=1;
    while(y){
        if(y&1) ret=((ll)ret*x)%P;
        x=((ll)x*x)%P;
        y>>=1;
    }
    return ret;
}
 
int cnt[N],t;
int vis[N],f[25][25][25];
 
int main()
{
    scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&P);
    n=sr+sb+sg;
    for(int i=0;i<m;i++)
        for(int j=1;j<=n;j++) scanf("%d",&cg[i][j]);
    for(int i=1;i<=n;i++) cg[m][i]=i;
     
    int ans=0,x;
    for(int i=0;i<=m;i++){
        memset(vis,0,sizeof(vis));
        memset(cnt,0,sizeof(cnt)); t=0;
        memset(f,0,sizeof(f));
        for(int j=1;j<=n;j++){
            if(vis[j]) continue;
            t++;
            x=j;
            while(!vis[x]) {
                vis[x]=1;
                cnt[t]++;
                x=cg[i][x];
            }
        }
        f[sr][sb][sg]=1;
        for(int j=1;j<=t;j++){
            for(int r=0;r<=sr;r++)
                for(int b=0;b<=sb;b++)
                    for(int g=0;g<=sg;g++){
                        if(r+cnt[j]<=sr) (f[r][b][g]+=f[r+cnt[j]][b][g])%=P;
                        if(b+cnt[j]<=sb) (f[r][b][g]+=f[r][b+cnt[j]][g])%=P;
                        if(g+cnt[j]<=sg) (f[r][b][g]+=f[r][b][g+cnt[j]])%=P;
                    }
        }
        (ans+=f[0][0][0])%=P;
    }
    printf("%d\n",((ll)ans*Pow_mod(m+1,P-2))%P);
     
    return 0;
}

[bzoj1004] [HNOI2008] Cards