[BZOJ1004] [HNOI2008] Cards (Polya定理)
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
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。
Source
Solution
$Polya$定理($Burnside$引理)戳这
其作用就是求出有几种本质不同的染色方案
由于每种颜色的个数有限制,需要用三维的$0/1$背包求出每一种置换下不动点方案数(注意不洗牌也是一种置换)
呃,需要用乘法逆元,否则你会死得很难看
1 #include <bits/stdc++.h> 2 using namespace std; 3 int p, x[65][65], f[25][25][25], siz[65]; 4 bool vis[65]; 5 6 int qpow(int a, int b) 7 { 8 int ans = 1; 9 for(; b; b >>= 1, a = a * a % p) 10 if(b & 1) ans = ans * a % p; 11 return ans; 12 } 13 14 int main() 15 { 16 int sr, sg, sb, m, inv, ans = 0, tot; 17 cin >> sr >> sb >> sg >> m >> p; 18 for(int i = 1; i <= m; ++i) 19 for(int j = 1; j <= sr + sg + sb; ++j) 20 cin >> x[i][j]; 21 for(int i = 1; i <= sr + sg + sb; ++i) 22 x[m + 1][i] = i; 23 for(int z = 1; z <= m + 1; ++z) 24 { 25 memset(f, 0, sizeof(f)); 26 memset(vis, 0, sizeof(vis)); 27 memset(siz, 0, sizeof(siz)); 28 f[0][0][0] = 1, tot = 0; 29 for(int i = 1; i <= sr + sg + sb; ++i) 30 if(!vis[i]) 31 { 32 ++tot; 33 for(int j = i; !vis[j]; j = x[z][j]) 34 vis[j] = true, ++siz[tot]; 35 } 36 for(int l = 1; l <= tot; ++l) 37 for(int i = sr; ~i; --i) 38 for(int j = sg; ~j; --j) 39 for(int k = sb; ~k; --k) 40 { 41 if(i >= siz[l]) 42 f[i][j][k] = (f[i][j][k] + f[i - siz[l]][j][k]) % p; 43 if(j >= siz[l]) 44 f[i][j][k] = (f[i][j][k] + f[i][j - siz[l]][k]) % p; 45 if(k >= siz[l]) 46 f[i][j][k] = (f[i][j][k] + f[i][j][k - siz[l]]) % p; 47 } 48 ans = (ans + f[sr][sg][sb]) % p; 49 } 50 cout << ans * qpow(m + 1, p - 2) % p << endl; 51 return 0; 52 }