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