[AHOI2009]中国象棋

AHOI

题意

求在$ncdot m​$的棋盘上摆放一些炮,使得任意两个炮不能互相攻击的方案数

题解

对于每一列,显然只能有0或1或2个炮,这是列中不能攻击的充要条件

令$f_{i,j,k}$为考虑前i行,其中有j列有1个炮,k列有两个炮的方案数,这也意味着有$m-i-j$列没有放棋子

分当前行放0或1或2个棋子讨论即可

调试记录

不必维护行的信息,在转移的时候行就是满足条件的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include <algorithm>
const int mo = 9999973;
const int maxn = 105;
using namespace std;
int f[maxn][maxn][maxn], n, m;
int (int x){
return 1ll * x * (x - 1) / 2 % mo;
}
int main() 大专栏  [AHOI2009]中国象棋{
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; j + k <= m; k++){
f[i][j][k] = f[i - 1][j][k];
if (k > 0) f[i][j][k] = (f[i][j][k] + 1ll * f[i - 1][j + 1][k - 1] * (j + 1) % mo) % mo;
if (j > 0) f[i][j][k] = (f[i][j][k] + 1ll * f[i - 1][j - 1][k] * (m - j - k + 1) % mo) % mo;
if (k > 1) f[i][j][k] = (f[i][j][k] + 1ll * f[i - 1][j + 2][k - 2] * X(j + 2) % mo) % mo;
if (k > 0) f[i][j][k] = (f[i][j][k] + 1ll * f[i - 1][j][k - 1] * j % mo * (m - j - k + 1) % mo) % mo;
if (j > 1) f[i][j][k] = (f[i][j][k] + 1ll * f[i - 1][j - 2][k] * X(m - j - k + 2) % mo) % mo;
}
}
int ans = 0;
for (int j = 0; j <= m; j++)
for (int k = 0; j + k <= m; k++)
ans = (ans + f[n][j][k]) % mo;
printf("%dn", ans);
return 0;
}
原文地址:https://www.cnblogs.com/lijianming180/p/12401974.html