您的位置:首页 > 其它

[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]。

代码:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: