题目描述
这次小可可想解决的难题和中国象棋有关,在一个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
然后我想到了压位dp,按3进制表示当前棋盘的状态,即某一列没有棋子,或者有一个,两个棋子,能过50分
接着可以发现,棋子的顺序是无所谓的,并不需要准确知道当前棋盘的状态
于是有了100分做法:dp[i][j][k]表示放了前i行,有j列是有1个棋子,有k列有两个棋子、
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<cctype> 5 #include<cstring> 6 #define mod 9999973 7 #define int long long 8 #define R register 9 using namespace std; 10 inline void in(int &x) 11 { 12 int f=1;x=0;char s=getchar(); 13 while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} 14 while(isdigit(s)){x=x*10+s-'0';s=getchar();} 15 x*=f; 16 } 17 int n,m,ans; 18 int f[108][108][108]; 19 inline int C(int x) 20 { 21 return ((x*(x-1))/2)%mod; 22 } 23 signed main() 24 { 25 in(n),in(m); 26 f[0][0][0]=1; 27 for(R int i=1;i<=n;i++) 28 { 29 for(R int j=0;j<=m;j++) 30 { 31 for(R int k=0;k<=m-j;k++) 32 { 33 f[i][j][k]=f[i-1][j][k]; 34 if(k>=1)(f[i][j][k]+=f[i-1][j+1][k-1]*(j+1)); 35 if(j>=1)(f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1)); 36 if(k>=2)(f[i][j][k]+=f[i-1][j+2][k-2]*(((j+2)*(j+1))/2)); 37 if(k>=1)(f[i][j][k]+=f[i-1][j][k-1]*j*(m-j-k+1)); 38 if(j>=2)(f[i][j][k]+=f[i-1][j-2][k]*C(m-j-k+2)); 39 f[i][j][k]%=mod; 40 } 41 } 42 } 43 for(R int i=0;i<=m;i++) 44 for(R int j=0;j<=m;j++) 45 (ans+=f[n][i][j])%=mod; 46 printf("%lld",(ans+mod)%mod); 47 }