题意
在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。 请问有多少种放置方法。
N,M <= 100
题解
发现每行每列都最多放两个,直接按行DP。
设表示到第行,有列放了个,列放了个。
那么这一行就有三种情况:
- 不放
- 放个,又有两种情况
- 放在之前没有棋子的列上
- 放在已经有个棋子的列上
- 放个,有三种情况
- 两个都放在没有棋子的列上
- 两个都放在已经有个棋子的列上
- 一个放在没有棋子的列上,一个放在已经有个棋子的列上
转移显然。
CODE
#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int mod = 9999973;
int f[MAXN][MAXN][MAXN], n, m;
inline int calc(int n) { return (1ll * n * (n-1) / 2) % mod; }
int main () {
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+j <= m; ++k) {
f[i][j][k] = f[i-1][j][k];
if(j) f[i][j][k] = (f[i][j][k] + 1ll * f[i-1][j-1][k] * (m-(j-1)-k) % mod) % mod;
if(k) f[i][j][k] = (f[i][j][k] + 1ll * f[i-1][j+1][k-1] * (j+1) % mod) % mod;
if(j>1) f[i][j][k] = (f[i][j][k] + 1ll * f[i-1][j-2][k] * calc(m-(j-2)-k) % mod) % mod;
if(k>1) f[i][j][k] = (f[i][j][k] + 1ll * f[i-1][j+2][k-2] * calc(j+2) % mod) % mod;
if(j) f[i][j][k] = (f[i][j][k] + 1ll * f[i-1][j][k-1] * (m-j-(k-1)) % mod * j % mod) % mod;
}
int ans = 0;
for(int j = 0; j <= m; ++j)
for(int k = 0; k+j <= m; ++k)
ans = (ans + f[n][j][k]) % mod;
printf("%d
", (ans + mod) % mod);
}