【BZOJ3294/洛谷3158】[CQOI2011]放棋子(組合數+DP)
阿新 • • 發佈:2018-12-13
題目:
分析:
某OIer兔崽子的此題程式碼中的三個函式名:dfs、ddfs、dddfs(充滿毒瘤的氣息
顯然,行與行之間、列與列之間是互相獨立的。考慮揹包,用\(f[k][i][j]\)表示用前\(k\)種顏色佔了\(i\)行\(j\)列的方案數,\(g[i][j]\)表示用顏色\(k\)佔據\(i\)行\(j\)列的方案數,\(c[i]\)表示顏色為\(i\)的棋子數,就有如下方程:
\[f[k][i][j]=\sum _{a=0}^i \sum_{b=0}^j f[k-1][i-a][j-b]\times g[a][b]\times C_{n-(i-a)}^a\times C_{m-(j-b)}^b(ab\geq c[i])\]
\(g[i][j]\)在算的時候注意要減去有空行或空列的情況(列舉有多少行、列不是空的)。注意要\(a=i\)且\(b=j\)的情況要跳過:
\[g[i][j]=C_{ij}^{c[k]}-\sum_{a=0}^i \sum_{b=0}^j g[a][b]\times C_i^a \times C_j^b(ij\geq c[k])\]
程式碼:
#include <cstdio> #include <algorithm> #include <cstring> #include <cctype> using namespace std; namespace zyt { template<typename T> inline void read(T &x) { char c; bool f = false; x = 0; do c = getchar(); while (c != '-' && !isdigit(c)); if (c == '-') f = true, c = getchar(); do x = x * 10 + c - '0', c = getchar(); while (isdigit(c)); if (f) x = -x; } template<typename T> inline void write(T x) { static char buf[20]; char *pos = buf; if (x < 0) putchar('-'), x = -x; do *pos++ = x % 10 + '0'; while (x /= 10); while (pos > buf) putchar(*--pos); } typedef long long ll; const int N = 40, T = 20, p = 1e9 + 9; int n, m, c, arr[T], C[N * N][N * N], f[T][N][N], g[N][N]; void init() { for (int i = 0; i < N * N; i++) { C[i][0] = 1; for (int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % p; } } int work() { init(); read(n), read(m), read(c); for (int i = 1; i <= c; i++) read(arr[i]); f[0][0][0] = 1; for (int k = 1; k <= c; k++) { memset(g, 0, sizeof(g)); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (i * j >= arr[k]) { g[i][j] = C[i * j][arr[k]]; for (int a = 0; a <= i; a++) for (int b = 0; b <= j; b++) { if (a != i || b != j) g[i][j] = (g[i][j] - (ll)g[a][b] * C[i][a] % p * C[j][b] % p + p) % p; } } } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) for (int a = 1; a <= i; a++) for (int b = 1; b <= j; b++) if (a * b >= arr[k]) f[k][i][j] = (f[k][i][j] + (ll)f[k - 1][i - a][j - b] * g[a][b] % p * C[n - (i - a)][a] % p * C[m - (j - b)][b]) % p; } int ans = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) ans = (ans + f[c][i][j]) % p; write(ans); return 0; } } int main() { return zyt::work(); }