标签:
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入格式:
一行包含两个整数N,M,之间由一个空格隔开。
输出格式:
总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
1 3
7
样例说明
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。
数据范围
100%的数据中N和M均不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
不用说算法也知道是DP
是一种神奇的DP
设F[i][j][k]表示第i行时 有j列放了0个炮,有k列放了1个炮 的方案数(-->有M-j-k列放了两个炮)
答案:把所有F[i][j][k]加起来就好了
转移:
这一行可以不放
那么直接加上dp[i-1][j][k]
放一个的话
可以把一列0变成1
可以把一列1变成2
放两个的话
可以把两列0变成1
可以把两列1变成2
还有 可以把一列0变成1 再把另外一列1变成2
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 typedef long long LL; 8 9 const int maxn=105; 10 const int mod=9999973; 11 12 int N,M; 13 LL F[maxn][maxn][maxn]; 14 15 LL zuhe[maxn]; 16 17 18 int main() 19 { 20 scanf("%d %d",&N,&M); 21 int i,j,k; 22 for(i=2;i<=M;i++) 23 zuhe[i]=i*(i-1)/2; 24 F[0][M][0]=1; 25 for(i=1;i<=N;i++) 26 { 27 for(j=0;j<=M;j++) 28 { 29 for(k=0;k<=M-j;k++) 30 { 31 F[i][j][k]+=F[i-1][j][k]; 32 F[i][j][k]+=F[i-1][j][k+1]*(k+1);//1 to 2 *1 33 if(k-1>=0) F[i][j][k]+=F[i-1][j+1][k-1]*(j+1);//0 to 1 *1 34 F[i][j][k]+=F[i-1][j+1][k]*(j+1)*k;//0 to 1 ,1 to 2 35 F[i][j][k]+=F[i-1][j][k+2]*zuhe[k+2];//1 to 2 *2 36 if(k-2>=0) F[i][j][k]+=F[i-1][j+2][k-2]*zuhe[j+2];//0 to 1 *2 37 F[i][j][k]%=mod; 38 } 39 } 40 } 41 LL ans=0; 42 for(j=0;j<=M;j++) 43 { 44 for(k=0;k<=M-j;k++) 45 ans+=F[N][j][k]; 46 ans%=mod; 47 } 48 cout<<ans<<endl; 49 return 0; 50 }
像我这个蒟蒻,ac了一道省选题,还是蛮高兴的
标签:
原文地址:http://www.cnblogs.com/cnblogsLSY/p/5785164.html