AHOI2009中国象棋

原题地址

题目描述

这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!

输入输出格式

输入格式:

一行包含两个整数N,M,之间由一个空格隔开。

输出格式:

总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。

输入输出样例

输入样例#1:

1
1 3

输出样例#1:

1
7

说明

样例说明

除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2 2 2-1=7种方案。

数据范围

100%的数据中N和M均不超过100

50%的数据中N和M至少有一个数不超过8

30%的数据中N和M均不超过6

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
首先要想出来,每行最多只能放两个棋子,这是显然的
于是决策就是一行一行地处理
棋子的顺序是无所谓的,并不需要准确知道当前棋盘的状态
dp[i][j][k]表示放了前i行,有j列是有1个棋子,有k列有两个棋子

#include <cstdio>
#define MOD 9999973
using namespace std;
long long n,m,ans;
long long f[101][101][101];
int main(){
scanf("%lld%lld",&n,&m);
f[0][0][0]=1;
for(int i=0;i<n;++i)
for(int j=0;j<=m;++j)
for(int k=0;j+k<=m;++k)
if(f[i][j][k]){
f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%MOD;
if(j>0)f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k]*j)%MOD;
if(m-j-k>0)f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%MOD;
if(m-j-k>=2)f[i+1][j+2][k]=(f[i+1][j+2][k]+f[i][j][k]*((m-j-k)*(m-j-k-1)/2))%MOD;
if(m-j-k>0&&j>=1)f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%MOD;
if(j>=2)f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+f[i][j][k]*(j*(j-1)/2))%MOD;
}
for(int i=0;i<=m;++i)
for(int j=0;i+j<=m;++j)
ans=(ans+f[n][i][j])%MOD;
printf("%lld",ans);
return 0;
}