P2051 中国象棋

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;
}

  

原文地址:https://www.cnblogs.com/wmq12138/p/10447692.html