【BZOJ1801】[Ahoi2009]chess 中国象棋 DP
【BZOJ1801】[Ahoi2009]chess 中国象棋
Description
在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧.
Input
一行包含两个整数N,M,中间用空格分开.
Output
输出所有的方案数,由于值比较大,输出其mod 9999973
Sample Input
1 3
Sample Output
7
HINT
除了在3个格子中都放满炮的的情况外,其它的都可以.
100%的数据中N,M不超过100
50%的数据中,N,M至少有一个数不超过8
30%的数据中,N,M均不超过6
题解:用f[k][i][j]表示前k行,有i列有1个炮,有j列有2个炮,即有k-i-j列有0个炮 的方案数
分以下情况讨论:
1.不放炮
2.放一个炮:a.在原本没有炮的列放
b.在原本有1个炮的列放
3.放两个炮:a.在原本没有炮的两列放
b.在原本有一个炮的两列放
c.一个在原本没有炮的列放,一个在原本有炮的列放
方程自己YY吧~
#include <cstdio> #include <iostream> #include <cstring> #define mod 9999973ll using namespace std; typedef long long ll; ll f[2][110][110],c[110][110]; ll n,m,ans; int main() { scanf("%d%d",&n,&m); int i,j,k; f[0][0][0]=1,c[0][0]=1; for(i=1;i<=m;i++) { c[i][0]=1; for(j=1;j<=2;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; } for(k=1;k<=n;k++) { for(i=0;i<=m;i++) { for(j=0;i+j<=m;j++) { f[k&1][i][j]=f[(k&1)^1][i][j]; if(i) f[k&1][i][j]+=f[(k&1)^1][i-1][j]*(m-i-j+1); f[k&1][i][j]%=mod; if(j) f[k&1][i][j]+=f[(k&1)^1][i+1][j-1]*(i+1); f[k&1][i][j]%=mod; if(j) f[k&1][i][j]+=f[(k&1)^1][i][j-1]*(m-i-j+1)*i; f[k&1][i][j]%=mod; if(j>1) f[k&1][i][j]+=f[(k&1)^1][i+2][j-2]*c[i+2][2]; f[k&1][i][j]%=mod; if(i>1) f[k&1][i][j]+=f[(k&1)^1][i-2][j]*c[m-i-j+2][2]; f[k&1][i][j]%=mod; } } } for(i=0;i<=m;i++) for(j=0;i+j<=m;j++) ans=(ans+f[n&1][i][j])%mod; printf("%lld",ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<