[BZOJ1004][HNOI2008]Cards(Burnside引理+DP)
2018-02-17 12:52
477 查看
加上一个置换123...n123...n,形成m+1m+1个置换。
根据Burnside引理,答案等于:
1m+1∑x=1m+1D(ax)1m+1∑x=1m+1D(ax)
D(ax)D(ax)表示在置换axax(第xx个置换)下,不变的元素(染色方案)个数。
对于每个1≤x≤m+11≤x≤m+1,怎么求D(ax)D(ax)呢?
首先把axax分循环节。可以得出,一种方案在置换axax下不变,等价于这种方案在axax的每个循环节内只有一种颜色。
如一种置换为2451324513,循环节为(1,2,4)(3,5)(1,2,4)(3,5),那么一种方案在置换axax下不变,等价于这种方案的第11张,第22张和第44张牌同色,第33张牌和第55张牌同色。
然后?DP!
设f[k][i][j]f[k][i][j]表示到了第kk个循环节,用了ii张红色jj张蓝色的方案数。边界f[0][0][0]=1f[0][0][0]=1。转移就是枚举第kk个循环节被染成的颜色(totktotk表示第kk个循环节包含的牌数):
f[k][i][j]=f[k−1][i−totk][j]+f[k−1][i][j−totk]+f[k−1][i][j]f[k][i][j]=f[k−1][i−totk][j]+f[k−1][i][j−totk]+f[k−1][i][j]
这样,D(ax)D(ax)就等于f[axf[ax的循环节个数][Sr][Sb]][Sr][Sb]。
代码:
根据Burnside引理,答案等于:
1m+1∑x=1m+1D(ax)1m+1∑x=1m+1D(ax)
D(ax)D(ax)表示在置换axax(第xx个置换)下,不变的元素(染色方案)个数。
对于每个1≤x≤m+11≤x≤m+1,怎么求D(ax)D(ax)呢?
首先把axax分循环节。可以得出,一种方案在置换axax下不变,等价于这种方案在axax的每个循环节内只有一种颜色。
如一种置换为2451324513,循环节为(1,2,4)(3,5)(1,2,4)(3,5),那么一种方案在置换axax下不变,等价于这种方案的第11张,第22张和第44张牌同色,第33张牌和第55张牌同色。
然后?DP!
设f[k][i][j]f[k][i][j]表示到了第kk个循环节,用了ii张红色jj张蓝色的方案数。边界f[0][0][0]=1f[0][0][0]=1。转移就是枚举第kk个循环节被染成的颜色(totktotk表示第kk个循环节包含的牌数):
f[k][i][j]=f[k−1][i−totk][j]+f[k−1][i][j−totk]+f[k−1][i][j]f[k][i][j]=f[k−1][i−totk][j]+f[k−1][i][j−totk]+f[k−1][i][j]
这样,D(ax)D(ax)就等于f[axf[ax的循环节个数][Sr][Sb]][Sr][Sb]。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } const int N = 66, M = 23; int n, Sr, Sb, Sg, m, MX, to , f [M][M]; bool vis ; int qpow(int a, int b) { int res = 1; while (b) b & 1 ? res = res * a % MX : 0, a = a * a % MX, b >>= 1; return res; } int main() { int i, j, k, h; n = (Sr = read()) + (Sb = read()) + (Sg = read()); m = read(); MX = read(); for (i = 1; i <= m; i++) for (j = 1; j <= n; j++) to[i][j] = read(); m++; for (j = 1; j <= n; j++) to[m][j] = j; int ans = 0; for (i = 1; i <= m; i++) { memset(vis, 0, sizeof(vis)); memset(f, 0, sizeof(f)); f[0][0][0] = 1; int t = 0; for (j = 1; j <= n; j++) if (!vis[j]) { int x = to[i][j], tot = 1; vis[j] = 1; t++; while (x != j) vis[x] = 1, x = to[i][x], tot++; for (k = 0; k <= Sr; k++) for (h = 0; h <= Sb; h++) { if (k >= tot) f[t][k][h] = (f[t][k][h] + f[t - 1][k - tot][h]) % MX; if (h >= tot) f[t][k][h] = (f[t][k][h] + f[t - 1][k][h - tot]) % MX; f[t][k][h] = (f[t][k][h] + f[t - 1][k][h]) % MX; } } ans = (ans + f[t][Sr][Sb]) % MX; } cout << ans * qpow(m, MX - 2) % MX << endl; return 0; }
相关文章推荐
- [bzoj 1004][HNOI 2008]Cards(Burnside引理+DP)
- [BZOJ1004][HNOI2008]Cards(Burnside引理+dp)
- bzoj1004: [HNOI2008]Cards(burnside引理+DP)
- 【bzoj1004】[HNOI2008]Cards burnside引理+dp
- 【BZOJ1004】【HNOI2008】Cards
- 【BZOJ】1004: [HNOI2008]Cards(置换群+polya+burnside)
- BZOJ 1004([HNOI2008]Cards-Polya计数+k背包)
- [bzoj1004][HNOI2008][Cards] (置换群+Burnside引理+动态规划)
- BZOJ 1004: [HNOI2008]Cards
- BZOJ1004: [HNOI2008]Cards
- 【BZOJ】【1004】【HNOI2008】Cards
- [BZOJ1004] [HNOI2008] Cards - 群论,Burnside引理,Polya定理
- [BZOJ 1004] [HNOI2008] Cards 【Burnside引理 + DP】
- bzoj 1004: [HNOI2008]Cards
- BZOJ 1004 [HNOI2008]Cards
- BZOJ1004 [HNOI2008]Cards
- BZOJ_1004_[HNOI2008]Cards_burnside+DP
- BZOJ 1004: [HNOI2008]Cards Burnside dp
- Bzoj1004 [HNOI2008]Cards
- 【bzoj 1004】 Cards 【HNOI2008】