bzoj 1004: [HNOI2008]Cards
这也是一道polya定理的题,只不过在求循环节数的时候由于有使用个数限制,所以不能直接快速幂,而是用DP求出每个置换的循环节。DP很简单,近乎于暴力=_=
上代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define N 100 #define M 25 using namespace std; int n, m, a[N]; int sb, sr, sg; int yu; int f[M][M][M]; int mi(int a, int b) { int ans = 1, zan = a; while (b) { if (b & 1) { ans *= zan; if (ans > yu) ans %= yu; } b >>= 1; zan *= zan; if (zan > yu) zan %= yu; } return ans; } int cal() { memset(f, 0, sizeof(f)); int cir[N] = {0}, cirnum = 0; bool vis[N] = {0}; for (int i = 1; i <= n; ++i) if (!vis[i]) { cirnum ++; cir[cirnum] = 1; vis[i] = 1; int x = a[i]; while (!vis[x]) { vis[x] = 1; cir[cirnum] ++; x = a[x]; } } f[0][0][0] = 1; for (int w = 1; w <= cirnum; ++w) for (int i = sr; i >= 0; --i) for (int j = sb; j >= 0; --j) for (int k = sg; k >= 0; --k) { if (i - cir[w] >= 0) f[i][j][k] += f[i-cir[w]][j][k]; if (f[i][j][k] > yu) f[i][j][k] %= yu; if (j - cir[w] >= 0) f[i][j][k] += f[i][j-cir[w]][k]; if (f[i][j][k] > yu) f[i][j][k] %= yu; if (k - cir[w] >= 0) f[i][j][k] += f[i][j][k-cir[w]]; if (f[i][j][k] > yu) f[i][j][k] %= yu; } return f[sr][sb][sg]; } int main() { scanf("%d%d%d%d%lld", &sr, &sb, &sg, &m, &yu); n = sr+sb+sg; int ans = 0; for (int i = 1; i <= n; ++i) a[i] = i; ans += cal(); if (ans > yu) ans %= yu; for (int i = 1; i <= m; ++i) { for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); ans += cal(); if (ans > yu) ans %= yu; } ans *= mi(m+1, yu-2)%yu; printf("%d\n", ans % yu); }