[AHOI2009]中国象棋
标签: 动态规划 棋盘型
题目描述
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入输出格式
输入格式:
一行包含两个整数N,M,之间由一个空格隔开。
输出格式:
总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
输入输出样例
输入样例#1:
1 3
输出样例#1:
7
题解
分析题目性质可得,每一行每一列的炮不能超过两个。(三个及其以上肯定会攻击到)
因此我们可以枚举每一行,看如何放炮:
放0个,放1个,放两个,以及放的位置。
可知,当我们放炮时,放炮的合法性会受到列的影响(不能超过三个),因此我们需要把每列炮的数量这个状态记录下来。
设f[i][j][k]表示第i行有j列有一个炮,k列有两个炮,m-j-k列没有炮的方案数。
那么转移的话分类讨论即可。
f[i][j][k] = (f[i][j][k] + f[i - 1][j][k]) % p; //不放
//放一个
if(j > 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k] * (m - j - k + 1) % p) % p; //放到没有炮的那一列中
if(j < m && k > 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 1][k - 1] * (j + 1) % p) % p; //放到一个炮的那一列中
//放两个
if(j > 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 2][k] * C(m - j - k + 2) % p) % p; //两个炮放到只有一个炮的列中
if(k > 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1] * j * (m - j - k + 1) % p) % p; //两个炮分别放到0炮的列中和1炮的列中
if(j + 2 <= m && k > 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 2][k - 2] * C(j + 2) % p) % p; //两个炮分别放到一炮的那一列中
代码
#include<bits/stdc++.h>
#define N 110
#define p 9999973
#define ll long long
using namespace std;
int n, m;
ll f[N][N][N];
ll C(ll x)
{
return (x * (x - 1) / 2) % p;
}
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]) % p; //不放
//放一个
if(j > 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k] * (m - j - k + 1) % p) % p; //放到没有炮的那一列中
if(j < m && k > 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 1][k - 1] * (j + 1) % p) % p; //放到一个炮的那一列中
//放两个
if(j > 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 2][k] * C(m - j - k + 2) % p) % p; //两个炮放到只有一个炮的列中
if(k > 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1] * j * (m - j - k + 1) % p) % p; //两个炮分别放到0炮的列中和1炮的列中
if(j + 2 <= m && k > 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 2][k - 2] * C(j + 2) % p) % p; //两个炮分别放到一炮的那一列中
}
ll ans = 0;
for(int j = 0; j <= m; j ++)
for(int k = 0; k + j <= m; k ++)
ans += f[n][j][k], ans %= p;
printf("%lld", ans);
return 0;
}