[AHOI2009] 中国象棋
题目大意:在一个(N)行(M)列的棋盘上,让你放若干个炮,求让这些炮不互相攻击的摆放方法有多少种
经过思考,我们可以发现,你按照行来枚举,和之前行的关系所在,只有不能放在那些摆放了两个炮的列上.
这样来DP
-
状态:设(f[i][j][k])为到(i)行为止,有(j)列放了一个棋子,有(k)列放了两个棋子,共有多少种可能的方案.
-
状态转移:代码中有注释的那几行就是
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int Mod = 9999973;
int n, m;
long long f[105][105][105], ans;
inline int C(int num){
return num * (num - 1) / 2;
}
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][j][k] + f[i - 1][j][k]) % Mod;//不放
if(j && m - j - k + 1 >= 1)
f[i][j][k] = (f[i][j][k] + (f[i - 1][j - 1][k] * (m - j - k + 1)) % Mod ) % Mod;//放一个在空着的列
if(k)
f[i][j][k] = (f[i][j][k] + (f[i - 1][j + 1][k - 1] * (j + 1)) % Mod ) % Mod;//放一个在j列上
if(j > 1 && m - j - k + 2 >= 2)
f[i][j][k] = (f[i][j][k] + (f[i - 1][j - 2][k] * C(m - j - k + 2)) % Mod ) % Mod;//放两个在空列上
if(k >= 2)
f[i][j][k] = (f[i][j][k] + (f[i - 1][j + 2][k - 2] * C(j + 2)) % Mod ) % Mod;//放在两个j列上
if(k >= 1 && j && m - k + 1 - j >= 1)
f[i][j][k] = (f[i][j][k] + (f[i - 1][j][k - 1] * ((m - k + 1 - j) * j) % Mod ) % Mod ) % Mod;//一个放在j列上,一个放在空列上
}
for(int i = 0; i <= m; ++i)
for(int j = 0; j + i <= m; ++j){
ans = (ans + f[n][i][j]) % Mod;
}
printf("%d
", ans);
return 0;
}
错误qwq
- 开(long long),不然乘的时候会炸掉
- 一个放在(j)列上,一个放在空列上的情况,是乘上(m-k+1-j)和(j)