题目描述
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入输出格式
输入格式:一行包含两个整数N,M,之间由一个空格隔开。
输出格式:总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
输入输出样例
输入样例#1:
1 3
输出样例#1:
7
说明
样例说明
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。
数据范围
100%的数据中N和M均不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
设f[i][sta]表示当前为第i列,每一列上的炮为sta,sta为三进制数,可是这样状态过多,实际上列与列之间是彼此独立的,只需要知道有几个列放了1个炮,几个列放了2个炮,那剩下的列就没有放炮。因此状态可设为dp[i][j][k]表示放了前i行,有j列是有1个棋子,有k列有两个棋子
#include<iostream>
#include<cstring>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=105,MOD=9999973;
int n,m;
long long ans=0;
long long f[MAXN][MAXN][MAXN];
int main()
{
ios::sync_with_stdio(false);
int i,j,k;
cin>>n>>m;
memset(f,0,sizeof(f));
f[0][0][0]=1;
f(i,1,n){
f(j,0,m){
f(k,0,m-j){
f[i][j][k]=f[i-1][j][k];
if(j>=1&&m-j+1-k>0) f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-j+1-k))%MOD;
if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1))%MOD;
if(j>=2&&m-j+2-k>0) f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*((m-j+2-k)*(m-j+1-k)/2))%MOD;
if(j>=1&&k>=1&&m-j-k+1>0) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*((m-j-k+1)*j))%MOD;
if(k>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*((j+2)*(j+1)/2))%MOD;
if(i==n) ans=(ans+f[n][j][k])%MOD;
}
}
}
cout<<ans<<endl;
return 0;
}