【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;
}
posted @ 2017-03-25 16:42  CQzhangyu  阅读(321)  评论(0编辑  收藏  举报