[P2051 [AHOI2009]中国象棋] DP

https://www.luogu.org/problemnew/show/P2051

题目描述

这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!

输入输出格式

输入格式:

 

一行包含两个整数N,M,之间由一个空格隔开。

 

输出格式:

 

总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。

 

输入输出样例

输入样例#1: 复制
1 3
输出样例#1: 复制
7

说明

样例说明

除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。

数据范围

100%的数据中N和M均不超过100

50%的数据中N和M至少有一个数不超过8

30%的数据中N和M均不超过6

题解:每行每列只能放置0~2个棋子,所以可以按行顺序DP,每行放置0~2个保证行合法(转移过程限制这个条件),用dp[i][j][k]表示前i行有j列有1个棋子,有k列有两个棋子,保证列合法(状态数组dp限制了这个条件)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 const ll mod=9999973;
 8 ll dp[105][105][105];
 9 ll C(ll x){
10     return x*(x-1)/2%mod;
11 }
12 int main(){
13     int n,m;
14     scanf("%d%d",&n,&m);
15     dp[0][0][0]=1;
16     ll ans=0;
17     for(int i=1;i<=n;i++){
18         for(int j=0;j<=m;j++){
19                 for(int k=0;k<=m;k++){
20                     dp[i][j][k]+=dp[i-1][j][k]%mod;
21                     dp[i][j][k]%=mod;
22                     if(k)dp[i][j][k]+=(dp[i-1][j+1][k-1]*(j+1))%mod;
23                     dp[i][j][k]%=mod;
24                     if(j)dp[i][j][k]+=dp[i-1][j-1][k]*(m-j+1-k)%mod;
25                     dp[i][j][k]%=mod;
26                     if(j>=2)dp[i][j][k]+=dp[i-1][j-2][k]*C(m-j+2-k)%mod;
27                     dp[i][j][k]%=mod;
28                     if(k>=2)dp[i][j][k]+=(dp[i-1][j+2][k-2]*C(j+2))%mod;
29                     dp[i][j][k]%=mod;
30                     if(k)dp[i][j][k]+=dp[i-1][j][k-1]*(j*(m-j+1-k))%mod;
31                     dp[i][j][k]%=mod;
32                     if(i==n)ans+=dp[i][j][k];
33                     ans%=mod;
34                 }
35         }
36 
37     }
38     cout<<ans <<endl;
39     return 0;
40 }
View Code

 

posted @ 2019-03-28 10:25  MekakuCityActor  阅读(136)  评论(0编辑  收藏  举报