其他分享
首页 > 其他分享> > P2051 [AHOI2009]中国象棋

P2051 [AHOI2009]中国象棋

作者:互联网

大致题意

给一个\(n×m\)的棋盘,在上面放若干个炮,求有多少种放置方法可以使没有一个炮可以攻击到另一个炮

分析

状压\(dp\)

观察发现,每行和每列至多只能放\(2\)个棋子

考虑到每列中已经摆放的棋子数量会影响到之后能摆放的棋子数,不妨设:

\(f[i][j][k]\)为前\(i\)行中,一共有\(j\)列放了一个棋子的列数,\(k\)列放了两个棋子的列数

考虑这一行中放的棋子的个数

1.不放:

\(f[i+1][j][k] += f[i][j][k]\)

2.放一个:

此时有一个棋子的列数会减一,有两个的列数会加一

\(f[i+1][j-1][k+1] +=f[i][j][k]×j\)

此时有一个棋子的列数会加一,有两个的列数不变

\(f[i+1][j+1][k] +=f[i][j][k]×(m-j-k)\)

3.放两个

此时有一个棋子的列数会加二,有两个的列数不变

\(f[i+1][j+1][k] +=f[i][j][k]×C(m-j-k)\)

此时有一个棋子的列数会减二,有两个的列数会加二

\(f[i+1][j-2][k+2] +=f[i][j][k]×C(j)\)

此时有一个棋子的列数不变,有两个棋子的列数会加一

\(f[i+1][j][k+1] +=f[i][j][k]×(m-j-k)×j\)

\(code:\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 110;
#define int long long
#define mo 9999973
#define C(x) (((x)*(x-1)/2)%mo)
int f[MAXN][MAXN][MAXN];
int n,m;
signed main(){
	cin>>n>>m;
	f[0][0][0] = 1;
	for(int i=0;i<=n;i++){
		for(int j=0;j<=m;j++){
			for(int k=0;k+j<=m;k++){
				if(f[i][j][k]){
					f[i+1][j][k] = (f[i][j][k]+f[i+1][j][k])%mo;
					if(j>=1) f[i+1][j-1][k+1] = (f[i+1][j-1][k+1]+f[i][j][k]*j)%mo;
					if(j>=1&&(m-j-k)>0) f[i+1][j][k+1] =(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%mo;
					if((m-j-k)>0) f[i+1][j+1][k] = (f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%mo;
					if(j>=2) f[i+1][j-2][k+2] = (f[i+1][j-2][k+2]+f[i][j][k]*C(j))%mo;
					if((m-j-k)>1) f[i+1][j+2][k] = (f[i+1][j+2][k]+f[i][j][k]*C(m-j-k))%mo;
				}
			}
		}
	}
	int ans = 0;
	for(int i=0;i<=m;i++){
		for(int j=0;j+i<=m;j++){
			ans = (ans+f[n][i][j])%mo;
		}
	}
	cout<<ans%mo;
}

坑点&&感想

标签:中国象棋,列数会,AHOI2009,mo,列上,P2051,int,棋子,列数
来源: https://www.cnblogs.com/xcxc82/p/13586341.html