Description |
在
行
列的棋盘上,放若干个炮可以是
个,使得没有任何一个炮可以攻击另一个炮,请问有多少种放置方法。
一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。
Solution |
每行每列最多放两个炮。
不难想到用 表示前 行放了 个炮,其中第 行放了 个,分别在 列和 列, 列放了 个炮, 列放了 个炮的方案数。其中 。
这样的DP时间和空间复杂度都是 的,可以过 的数据,考虑怎样优化。
考虑怎样把 合成一个。不妨先做每行每列只放一个的,再把它用乘法原理合并成每行每列放两个的。
那么用 表示前 行放了 个炮,其中第 行的炮放在了第 列,第 列有 个炮的方案数( 表示不放)。
但最后的答案并不能直接平方,因为会有重复的情况,比如:
这怎么办呢?
劳资弃了上面的想法QAQ
设 表示前 行有 列是一个棋子, 列有两个棋子的方案数。
那么
这题跟 好像啊。
Error |
一上来就想错,没有仔细验证……
这个式子,要保证 才行,因为要把一个有一个棋子的列变成有两个棋子的。
初始化直接让 就可以。
Code |
#include <cstdio>
const int N = 105, P = 9999973;
int f[N][N][N];
int main() {
int n, m; scanf("%d%d", &n, &m);
f[0][0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
for (int k = 0; k <= m - j; ++k) {
f[i][j][k] = f[i-1][j][k];
if (j > 0) f[i][j][k] = (f[i][j][k] + 1LL * f[i-1][j-1][k] * (m - j - k + 1)) % P;
if (j > 1) f[i][j][k] = (f[i][j][k] + 1LL * f[i-1][j-2][k] * (m - j - k + 2) * (m - j - k + 1) / 2) % P;
if (j < m && k > 0) (f[i][j][k] = f[i][j][k] + 1LL * f[i-1][j+1][k-1] * (j + 1)) % P;
if (j > 0 && k > 0) f[i][j][k] = (f[i][j][k] + 1LL * f[i-1][j][k-1] * (m - j - k + 1) * j) % P;
if (j < m - 1 && k > 1) f[i][j][k] = (f[i][j][k] + 1LL * f[i-1][j+2][k-2] * (j + 2) * (j + 1) / 2) % P;
}
}
}
int ans = 0;
for (int j = 0; j <= m; ++j)
for (int k = 0; k <= m - j; ++k)
ans = (ans + f[n][j][k]) % P;
printf("%d\n", ans);
return 0;
}
QAQ另附上每行每列只有一个棋子的代码:
#include <cstdio>
const int N = 105, P = 9999973;
int f[N][N][N][2];
int main() {
int n, m; scanf("%d%d", &n, &m);
for (int i = 0; i <= m; ++i) f[0][0][i][0] = f[0][0][i][1] = 1;
for (int i = 1; i <= n; ++i) { //前i行
for (int j = 0; j <= i; ++j) { //放了j个棋子
int sum = 0;
if (j) for (int k = 1; k <= m; ++k) { //第i行放一个棋子在第k列
f[i][j][k][1] = (f[i][j][k][1] + f[i-1][j-1][k][0]) % P;
sum = (sum + f[i][j][k][1]) % P;
}
for (int k = 0; k <= m; ++k) { //第i行不放棋子
if (j == 0 && k) break;
f[i][j][0][1] = (f[i][j][0][1] + f[i-1][j][k][1]) % P;
sum = (sum + f[i][j][0][1]) % P;
}
for (int k = 1; k <= m; ++k) { //第k列没有棋子
f[i][j][k][0] = (sum - f[i][j][k][1] + P) % P;
}
}
}
int ans = 0;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= m; ++j)
ans = (ans + f[n][i][j][1]) % P;
printf("%d\n", ans);
return 0;
}