[bzoj1004] [HNOI2008] Cards
Description
小春現在很清閑,面對書桌上的 \(N\) 張牌,他決定給每張染色,目前小春只有 \(3\) 種顏色:紅色,藍色,綠色.他詢問 \(Sun\) 有多少種染色方案, \(Sun\) 很快就給出了答案.進一步,小春要求染出 \(Sr\) 張紅色, \(Sb\) 張藍色, \(Sg\) 張絕色.他又詢問有多少種方案, \(Sun\) 想了一下,又給出了正確答案. 最後小春發明了 \(M\) 種不同的洗牌法,這裏他又問 \(Sun\) 有多少種不同的染色方案.兩種染色方法相同當且僅當其中一種可以通過任意的洗牌法(即可以使用多種洗牌法,而每種方法可以使用多次)洗成另一種. \(Sun\)
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\) 引理的典型應用題。
預備知識
置換:在集合論中,一個集合的置換是從該集合映至自身的雙射。
它是一種運算
置換群
簡單來說,就是若幹置換組成的集合,且滿足“群”的特點,即:
\(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