【BZOJ】1801 [Ahoi2009]chess 中国象棋(dp)

题目

传送门:QWQ

分析

发现我们关心的不是棋子的位置,我们只关心棋子数量就ok。

首先每行每列最多两个棋子。这是显然的。

然后我觉得本题最难的部分就是对行进行讨论,蒟蒻我一直被限制在了对格点讨论。。。。

$dp[i][j][k] $放了前$i$行,有$j$列有1个棋子,有$k$列有2个棋子。转移就很显然了。

代码

 1 #include <bits/stdc++.h>
 2 typedef long long ll;
 3 const int maxn=105;const ll MOD=9999973;
 4 
 5 ll dp[maxn][maxn][maxn];
 6 //dp[i][j][k] 放了前i行,有j列有1个棋子,有k列有2个棋子
 7 ll num(int x){return ll(x)*ll(x-1)/2;}
 8 using namespace std;
 9 int main(){
10     int n,m;scanf("%d%d",&n,&m);
11     dp[0][0][0]=1;
12     for(int i=0;i<n;i++){ //放第i+1行
13         for(int j=0;j<=m;j++){
14             for(int k=0;k+j<=m;k++){
15                 dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][j][k])%MOD;
16                 if(m-j-k>=1) dp[i+1][j+1][k]=(dp[i+1][j+1][k]+dp[i][j][k]*(m-j-k))%MOD; 
17                 if(j>=1) dp[i+1][j-1][k+1]=(dp[i+1][j-1][k+1]+dp[i][j][k]*j)%MOD;
18                 if(m-j-k>=2) dp[i+1][j+2][k]=(dp[i+1][j+2][k]+dp[i][j][k]*num(m-j-k))%MOD;
19                 if(j>=2) dp[i+1][j-2][k+2]=(dp[i+1][j-2][k+2]+dp[i][j][k]*num(j))%MOD;
20                 if(m-j-k>=1 && j>=1) dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k]*(m-j-k)*j)%MOD;    
21             }
22         }
23     }
24     ll ans=0;
25     for(int i=0;i<=m;i++)
26         for(int j=0;j+i<=m;j++)
27             ans=(ans+dp[n][i][j])%MOD;
28     printf("%lld\n",ans);
29     return 0;
30 }

猜你喜欢

转载自www.cnblogs.com/noblex/p/9420764.html