10.10T6 计数DP(神奇的状态)
Description
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
Input
一行包含两个整数N,M,之间由一个空格隔开。
Output
总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
Sample Input
1 3
Sample Output
7
Hint
【样例说明】
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。
【数据规模】
100%的数据中N和M不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。
【数据规模】
100%的数据中N和M不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
神奇的状态f[i][j][k]代表前 i 行中 j 列没放棋子,k列放1个棋子,m-j-k列放了两个棋子
然后分类讨论1个2个的情况,具体在代码里面,不再赘述
为什么只讨论到两个。。。。因为一行最多放两个。。。
太神奇了
code:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 long long f[101][300][301],ans; 5 int main(){ 6 long long n,m; 7 cin>>n>>m; 8 f[0][m][0]=1; 9 for(int i=1;i<=n;i++){ 10 for(int j=0;j<=m;j++){ 11 for(int k=0;k+j<=m;k++){ 12 f[i][j][k]+=f[i-1][j][k];//不放 13 if(k)f[i][j][k]+=f[i-1][j+1][k-1]*(j+1);//一个放在原来没有的地方,0个减少,1个增多 14 if(m-k-j)f[i][j][k]+=f[i-1][j][k+1]*(k+1);// 放在原来有1个的上面,1个减少,2个增加 15 if(k&&(m-k-j))f[i][j][k]+=f[i-1][j+1][k]*(j+1)*k;//一个放在没有的地方,一个放在1个的地方 16 if(m-j-k>=2)f[i][j][k]+=f[i-1][j][k+2]*(k+2)*(k+1)/2;//两个都放在1的地方 17 if(k>=2)f[i][j][k]+=f[i-1][j+2][k-2]*(j+2)*(j+1)/2;//两个都放在没有的地方 18 f[i][j][k]%=9999973; 19 } 20 } 21 } 22 for(int j=0;j<=m;j++){ 23 for(int k=0;j+k<=m;k++){ 24 ans+=f[n][j][k]; 25 ans%=9999973; 26 } 27 } 28 cout<<ans<<endl; 29 }
over