[BZOJ 1801] [Ahoi2009]chess 中国象棋 【DP】
题目链接:BZOJ - 1801
题目分析
对于50%的数据是可以直接状压 DP 的。
对于100%的数据,使用递推的 DP 。(或者这只叫递推不叫 DP ?)
可以发现,每一行和每一列的棋子个数不能超过 2 个。
用 f[i][j][k] 表示前 i 行,有 j 列有 1 个棋子,有 k 列有 2 个棋子的方案数。(有 0 个棋子的列数可以用 m - j - k 得到。)
初始状态 f[0][0][0] = 1;
转移时从第 i - 1 行转移过来,由于一行最多放 2 个棋子,所以可以讨论各种情况,转移一下。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MaxN = 100 + 5;
typedef long long LL;
const LL Mod = 9999973;
int n, m;
LL Ans;
LL f[MaxN][MaxN][MaxN];
LL C2(int a) {
LL ret;
ret = (LL)a * (LL)(a - 1) / 2ll % Mod;
return ret;
}
int main()
{
scanf("%d%d", &n, &m);
f[0][0][0] = 1;
Ans = 0ll;
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 >= 1) f[i][j][k] = (f[i][j][k] + (f[i - 1][j - 1][k] * (LL)(m - (j - 1) - k) % Mod)) % Mod;
if (k >= 1) f[i][j][k] = (f[i][j][k] + (f[i - 1][j + 1][k - 1] * (LL)(j + 1) % Mod)) % Mod;
if (j >= 2) f[i][j][k] = (f[i][j][k] + (f[i - 1][j - 2][k] * C2(m - (j - 2) - k) % Mod)) % Mod;
if (k >= 2) f[i][j][k] = (f[i][j][k] + (f[i - 1][j + 2][k - 2] * C2(j + 2) % Mod)) % Mod;
if (j >= 1 && k >= 1) f[i][j][k] = (f[i][j][k] + (f[i - 1][j][k - 1]) * (LL)(j) * (LL)(m - j - (k - 1)) % Mod) % Mod;
if (i == n) Ans = (Ans + f[i][j][k]) % Mod;
}
}
}
printf("%lld\n", Ans);
return 0;
}

浙公网安备 33010602011771号