[AHOI2009] 中国象棋
[AHOI2009] 中国象棋
蛮简单的一道 \(DP\) .
显然, 每行每列都最多只有 \(2\) 个炮, 所以我们设 \(f[i][j][k]\) 表示第 \(i\) 行, \(j\) 列有 \(1\) 个炮, \(k\) 列有 \(2\) 个炮的方案数.
然后转移就很简单了, 只需要枚举当前行放的一个或者两个炮放到哪里就行了.
像这种合法不合法只与单行或单列的数量有关的, 我们设状态就可以只存数量为多少的行或列的数量就可以了, 转移的时候用组合来计算我们共有多少种转移方案.
\(code:\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read() {
int x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * f;
}
const int N = 105, mod = 9999973;
int n, m;
ll ans, f[N][N][N];
int main() {
n = read(), m = read();
f[0][0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = m; j >= 0; j--) {
for (int k = m - j; k >= 0; k--) {
f[i][j][k] += f[i - 1][j][k];
if (m - j - k) f[i][j + 1][k] = (f[i][j + 1][k] + f[i - 1][j][k] * (m - j - k)) % mod;
if (m - j - k > 1) f[i][j + 2][k] = (f[i][j + 2][k] + (f[i - 1][j][k] * (m - j - k) * (m - j - k - 1) >> 1)) % mod;
if (j) f[i][j - 1][k + 1] = (f[i][j - 1][k + 1] + f[i - 1][j][k] * j) % mod;
if (j > 1) f[i][j - 2][k + 2] = (f[i][j - 2][k + 2] + (f[i - 1][j][k] * j * (j - 1) >> 1)) % mod;
if (m - j - k && j) f[i][j][k + 1] = (f[i][j][k + 1] + f[i - 1][j][k] * j * (m - j - k)) % mod;
}
}
}
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= m - i; j++) {
ans += f[n][i][j];
}
}
printf("%lld", ans % mod);
return 0;
}
看不见我看不见我看不见我