1. 程式人生 > >【BZOJ1004】Cards(組合數學,Burnside引理)

【BZOJ1004】Cards(組合數學,Burnside引理)

getchar 多次 等價 要求 std tdi cst 多少 存在

【BZOJ1004】Cards(組合數學,Burnside引理)

題面

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}<=20。

題解

Burnside引理:
對於一個置換群
等價類的個數,等於所有置換的不動點的平均數

所以,這道題目相當於有\(m+1\)個置換
求總的不動點個數
其中,置換包括不變和題目給定的\(m\)

然後是求不動點的個數的問題
每一個置換相當於若幹個循環
如果是不動點的話,
循環中的每個點的顏色應當相同
於是大力跑一個01背包就好了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define MAX 100 #define MOD P inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int s1,s2,s3,m,P,n,ans; int a[MAX][MAX],size[MAX]; int f[MAX][MAX][MAX]; bool vis[MAX]; int fpow(int a,int b) { int s=1; while(b){if(b&1)s=1ll*s*a%P;a=1ll*a*a%P;b>>=1;} return s; } int DP(int x)//求關於第x置換的不動點的個數 { memset(size,0,sizeof(size)); memset(vis,0,sizeof(vis)); int sum=0;//拆成循環 for(int i=1;i<=n;++i) if(!vis[i]) { size[++sum]=1;vis[i]=true; int p=i; while(!vis[a[x][p]])size[sum]++,vis[p=a[x][p]]=true; } memset(f,0,sizeof(f)); f[0][0][0]=1; for(int t=1;t<=sum;++t) for(int i=s1;i>=0;--i) for(int j=s2;j>=0;--j) for(int k=s3;k>=0;--k) { if(i>=size[t])f[i][j][k]=(f[i][j][k]+f[i-size[t]][j][k])%MOD; if(j>=size[t])f[i][j][k]=(f[i][j][k]+f[i][j-size[t]][k])%MOD; if(k>=size[t])f[i][j][k]=(f[i][j][k]+f[i][j][k-size[t]])%MOD; } return f[s1][s2][s3]; } int main() { s1=read();s2=read();s3=read();m=read();P=read(); n=s1+s2+s3; for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) a[i][j]=read(); ++m; for(int i=1;i<=n;++i)a[m][i]=i;//不動也是一種置換 for(int i=1;i<=m;++i) ans=(ans+DP(i))%MOD; printf("%lld\n",1ll*ans*fpow(m,P-2)%P); return 0; }

【BZOJ1004】Cards(組合數學,Burnside引理)