1. 程式人生 > >【BZOJ】1801 [Ahoi2009]chess 中國象棋(dp)

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

發現 lin max def %d print class () line

題目

傳送門: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 }

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