BZOJ1004 HNOI2008 Cards Burnside引理、背包
阿新 • • 發佈:2019-01-30
ctype a + b getchar set sign 既然 getc sig .com
傳送門
在沒做這道題之前天真的我以為\(Polya\)可以完全替代\(Burnside\)
考慮\(Burnside\)引理,它要求的是對於置換群中的每一種置換的不動點的數量。
既然是不動點,那麽對於這一個置換中的一個輪換,這個不動點中輪換裏所有位置的顏色都必須相同。
然後題目就轉化成了一個背包。
#include<iostream> #include<cstdio> #include<cstdlib> #include<ctime> #include<cctype> #include<algorithm> #include<cstring> #include<iomanip> #include<queue> #include<map> #include<set> #include<bitset> #include<stack> #include<vector> #include<cmath> //This code is written by Itst using namespace std; inline int read(){ int a = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)){ a = a * 10 + c - 48; c = getchar(); } return a; } int dp[21][21][21] , cg[61]; int sr , sb , sg , N , M , P , sum; bool vis[61]; inline int poww(int a , int b){ int times = 1; while(b){ if(b & 1) times = times * a % P; a = a * a % P; b >>= 1; } return times; } inline int calcLen(int x){ int cnt = 0; while(!vis[x]){ vis[x] = 1; x = cg[x]; ++cnt; } return cnt; } inline void add(int& a , int b){ a = a + b >= P ? a + b - P : a + b; } void calc(){ memset(vis , 0 , sizeof(vis)); memset(dp , 0 , sizeof(dp)); dp[0][0][0] = 1; for(int i = 1 ; i <= N ; ++i) if(!vis[i]){ int t = calcLen(i); for(int j = sr ; j >= 0 ; --j) for(int k = sb ; k >= 0 ; --k) for(int l = sg ; l >= 0 ; --l){ if(j >= t) add(dp[j][k][l] , dp[j - t][k][l]); if(k >= t) add(dp[j][k][l] , dp[j][k - t][l]); if(l >= t) add(dp[j][k][l] , dp[j][k][l - t]); } } add(sum , dp[sr][sb][sg]); } signed main(){ #ifndef ONLINE_JUDGE //freopen("in" , "r" , stdin); //freopen("out" , "w" , stdout); #endif sr = read(); sb = read(); sg = read(); N = sr + sb + sg; M = read(); P = read(); for(int i = 1 ; i <= N ; ++i) cg[i] = i; calc(); for(int i = 1 ; i <= M ; ++i){ for(int j = 1 ; j <= N ; ++j) cg[j] = read(); calc(); } cout << sum * poww(M + 1 , P - 2) % P; return 0; }
BZOJ1004 HNOI2008 Cards Burnside引理、背包