题意
摆。
题解
用背包维护不定点,套 Burside 引理。
代码
const int N = 30, M = 70;
inline ll Read() {
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
namespace Main {
int sr, sb, sg, n, m, mod;
int f[N][N][N];
int a[M], siz[N], vis[N], cnt;
int add(int a, int b) { return a + b > mod? a + b - mod: a + b; }
int dec(int a, int b) { return a - b < 0? a - b + mod: a - b; }
int mul(int a, int b) { return 1ll * a * b % mod; }
int qpow (int a, ll b) {
int ans = 1;
for (; b; b >>= 1, a = mul(a, a))
if (b & 1) ans = mul(ans, a);
return ans;
}
int ans;
void dp (int n) {
memset (f, 0, sizeof f);
f[0][0][0] = 1;
for (int i = 1; i <= n; i++)
for (int r = sr; ~r; --r)
for (int b = sb; ~b; --b)
for (int g = sg; ~g; --g) {
if (r >= siz[i]) f[r][b][g] = add(f[r][b][g], f[r - siz[i]][b][g]);
if (b >= siz[i]) f[r][b][g] = add(f[r][b][g], f[r][b - siz[i]][g]);
if (g >= siz[i]) f[r][b][g] = add(f[r][b][g], f[r][b][g - siz[i]]);
}
ans = add(ans, f[sr][sb][sg]);
}
int main () {
sr = Read(), sb = Read(), sg = Read(), m = Read(), mod = Read();
n = sr + sb + sg;
for (int i = 1; i <= n; i++) siz[i] = 1;
dp(n);
for (int k = 1; k <= m; k++) {
for (int i = 1; i <= n; i++) a[i] = Read();
cnt = 0;
memset (vis, 0, sizeof vis);
for (int i = 1; i <= n; i++) {
if (vis[i]) continue;
vis[i] = 1;
int tmp = 1;
for (int j = a[i]; j != i; j = a[j]) {
vis[j] = 1;
tmp++;
}
siz[++cnt] = tmp;
}
dp(cnt);
}
printf ("%d\n", mul(ans, qpow(m + 1, mod - 2)));
return 0;
}
}
int main () {
string str = "";
// freopen((str + ".in").c_str(), "r", stdin);
// freopen((str + ".out").c_str(), "w", stdout);
Main::main();
return 0;
}
EOF