P2051 [AHOI2009] 中国象棋 题解

DP好题?

首先确定,每一行/列只能放至多两个棋子,这么少,所以我们的状态肯定和棋子数有关。

由于我们不关注具体的方案数,所以我们不妨只关心对应棋子数量的行/列的数量。同时,由于考虑行和列都是一样的,所以我们不妨用行递推。

所以我们设 dpi,j,k 表示当前放到第 i 行,有 j 列有1个棋子,有 k 列有2个棋子下的方案数。

容易写出转移方程如下:

一、 若不放棋子

  1. 直接继承 dpi1,j,k

二、 若放一个棋子

  1. 若放在有零个棋子的列
    dpi,j,k += dpi1,j1,k ×(mj+1k)
    放在有零个棋子的列,那么现在和原来相比多了一个有一个棋子的列,所以j1,而放在任意一个零列都可以,所以要乘mj+1k

  2. 若放在有一个棋子的列
    dpi,j,k += dpi1,j+1,k1 ×(j+1)
    因为你放在有一个棋子的列,有一个棋子的列的数量就减一了,所以对应转移过来应该是加一,而放在这j+1列都可以,所以要乘j+1

三、若放两个棋子

  1. 若一个放在零个棋子的列,一个放在一个棋子的列
    dpi,j,k += dpi1,j,k1 ×(mjk+1)×j
    这样就会让两个棋子的列多出一个,所以k1,而放在零个棋子的列有mjk+1,放在一个棋子的列有j,所以相乘。

  2. 若两个都放在一个棋子的列
    dpi,j,k += dpi1,j+2,k2 × (j+22)
    j+2 个地方都可以选,放两个。

  3. 若两个都放在零个棋子的列
    dpi,j,k += dpi1,j2,k ×(mjk+22)
    同上。

再多显然不可能了。
讨论结束。

Code

#include<bits/stdc++.h>
using namespace std;
const int mod=9999973;
int n,m;
long long dp[105][105][105];
long long ans;
int main(){
	scanf("%d %d",&n,&m);
	dp[0][0][0]=1;
	for(int i=1;i<=n;++i){
		for(int j=0;j<=m;++j){
			for(int k=0;k<=m-j;++k){
				dp[i][j][k]=dp[i-1][j][k]%mod;
				if(j>=1) dp[i][j][k]+=dp[i-1][j-1][k]*(m-j-k+1)%mod,dp[i][j][k]%=mod;
				if(k>=1) dp[i][j][k]+=dp[i-1][j+1][k-1]*(j+1)%mod,dp[i][j][k]%=mod;
				if(k>=1) dp[i][j][k]+=(dp[i-1][j][k-1]*(m-j-k+1)%mod)*j%mod,dp[i][j][k]%=mod;
				dp[i][j][k]+=dp[i-1][j+2][k-2]*(j+2)*(j+1)/2%mod,dp[i][j][k]%=mod;
				if(j>=2) dp[i][j][k]+=dp[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2%mod,dp[i][j][k]%=mod;
			}
		}
	}
	for(int i=0;i<=m;++i){
		for(int j=0;j<=m;++j) ans+=dp[n][i][j],ans%=mod;
	}
	printf("%lld",ans);
	return 0;
}
posted @   mountzhu  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示