[bzoj1801][Ahoi2009]chess 中国象棋

题目大意:给定一个$n imes m$的棋盘,问有多少种不同的放置炮的方案使得任意两个炮不能互相攻击。

题解:$f_{i,j,k}$表示到了第$i$行,前面有$j$列有一个炮,有$k$列有两个炮

转移懒得写,见代码

卡点:

C++ Code:

#include <cstdio>
#define maxn 111
using namespace std;
const int mod = 9999973;
int n, m;
long long f[maxn][maxn][maxn], ans;
long long C(long long a, long long b) {
	b %= mod;
	if (b == 1) return a % mod;
	if (b == 2) return (a * (a - 1) >> 1) % mod;
	return 20040826;
}
void up(long long &a, long long b) {
	a = (a + b) % mod;
}
int main() {
	scanf("%d%d", &n, &m);
	f[0][0][0] = 1;
	for (int i = 1; i <= m; i++) {
		for (int j = 0; j <= n; j++) {
			for (int k = 0; k + j <= n; k++) {
				long long tmp = f[i - 1][j][k];
				if (tmp) {
					up(f[i][j][k], tmp);
					up(f[i][j + 2][k], tmp * C(n - k - j, 2));
					up(f[i][j + 1][k], tmp * C(n - k - j, 1));
					up(f[i][j][k + 1], tmp * C(j, 1) % mod * C(n - k - j, 1));
					if (j) up(f[i][j - 1][k + 1], tmp * C(j, 1));
					if (j > 1) up(f[i][j - 2][k + 2], tmp * C(j, 2));
				}
			}
		}
	}
	for (int i = 0; i <= n; i++) {
		for (int j = 0; i + j <= n; j++) up(ans, f[m][i][j]);
	}
	printf("%lld
", ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9506486.html