P2051 中国象棋
题目描述
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入输出格式
输入格式:
一行包含两个整数N,M,之间由一个空格隔开。
输出格式:
总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
- 思路:用f[i][j][k]表示前i行,有j列只有1个棋子,有k列有2个棋子的方案数
- 代码:
#include <cstdio> #include <algorithm> #include <cctype> #include <iostream> #include <cstring> using namespace std; #define res register int typedef long long LL; const int N=110; const int mod=9999973; int n,m; LL f[N][N][N];//前i行已经放好,其中只放了一个的列有j列,放了两个的列有k列 inline int calc(int x)//在x个数中选2个的方案数 { return x*(x-1)/2; } int main() { scanf("%d %d",&n,&m); f[0][0][0]=1; for(res i=0 ; i<=n-1 ; ++i) for(res j=0 ; j<=m ; ++j) for(res k=0 ; k+j<=m ; ++k) if(f[i][j][k]) { f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod; if(m-j-k>=1)//放1个在有空余的列 f[i+1][j+1][k]=(f[i+1][j+1][k]+(m-j-k)*f[i][j][k])%mod; if(j>=1)//放1个在已经有 f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+j*f[i][j][k])%mod; if(m-j-k>=2) f[i+1][j+2][k]=(f[i+1][j+2][k]+calc(m-j-k)*f[i][j][k])%mod; if(m-j-k>=1 && j>=1)//放2个,1个在已经有的,另一个在没有的 f[i+1][j][k+1]= (f[i+1][j][k+1]+j*(m-j-k)*f[i][j][k])%mod; if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+calc(j)*f[i][j][k])%mod; } LL ans=0; for(res i=0 ; i<=m ; ++i) for(res j=0 ; i+j<=m ; ++j) ans=(ans+f[n][i][j])%mod; cout<<ans<<endl; return 0; }