【插头DP】HDU 4804 Campus Design
通道:http://acm.hdu.edu.cn/showproblem.php?pid=4804
题意:用[C,D]个1×1的方格,和任意个1×2的方格去覆盖N*M的网格,有阻碍,的方法数。
思路:dp[cur][j][k]:当前状态为cur,用了j个1×1的方格时状态为k的方案数。
代码:
1 #include <cstdio> 2 #include <cstring> 3 4 const int MOD = 1000000007; 5 6 int n, m, c, d; 7 long long dp[2][25][1222]; 8 char g[105][15]; 9 10 int main() { 11 while (4 == scanf("%d%d%d%d", &n, &m, &c, &d)) { 12 int maxs = 1 << m; 13 int cur = 0; 14 memset(dp[cur], 0, sizeof dp[cur]); 15 dp[cur][0][maxs - 1] = 1; 16 for (int i = 0; i < n; ++i) 17 scanf("%s", g[i]); 18 for (int i = 0; i < n; ++i) { 19 for (int j = 0; j < m; ++j) { 20 memset(dp[cur ^ 1], 0, sizeof dp[cur ^ 1]); 21 if (g[i][j] != '0') { 22 for (int k = 0; k <= d; ++k) { 23 for (int s = 0; s < maxs; ++s) { 24 if (k && (s >> j & 1)) 25 dp[cur ^ 1][k][s] = (dp[cur ^ 1][k][s] + dp[cur][k - 1][s]) % MOD;//放1X1 26 if (j && !(s&1<<(j-1)) && (s&1<<j)) 27 dp[cur ^ 1][k][s|1<<(j-1)] = (dp[cur ^ 1][k][s|1<<(j-1)] + dp[cur][k][s]) % MOD;//横放1X2 28 dp[cur ^ 1][k][s^1<<j] = (dp[cur ^ 1][k][s^1<<j] + dp[cur][k][s]) % MOD;//竖放1X2 29 } 30 } 31 } 32 else { 33 for (int k = 0; k <= d; ++k) { 34 for (int s = 0; s < maxs; ++s) { 35 if ((s&1<<j)) 36 dp[cur ^ 1][k][s] = (dp[cur ^ 1][k][s] + dp[cur][k][s]) % MOD;//不能放的情况,和放1X1类似 37 } 38 } 39 } 40 cur ^= 1; 41 } 42 } 43 long long ans = 0; 44 for (int i = c; i <= d; i++) 45 ans = (ans + dp[cur][i][maxs - 1]) % MOD; 46 printf("%lld\n", ans); 47 } 48 return 0; 49 }