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; }
|