1. 程式人生 > >動態規劃 BZOJ1801 [Ahoi2009]chess 中國象棋

動態規劃 BZOJ1801 [Ahoi2009]chess 中國象棋

vtp size bom hint sizeof ecg 然而 cda 中國象棋

1801: [Ahoi2009]chess 中國象棋

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 1861 Solved: 1068
[Submit][Status][Discuss]

Description

在N行M列的棋盤上,放若幹個炮可以是0個,使得沒有任何一個炮可以攻擊另一個炮。 請問有多少種放置方法,中國像棋中炮的行走方式大家應該很清楚吧.

Input

一行包含兩個整數N,M,中間用空格分開.

Output

輸出所有的方案數,由於值比較大,輸出其mod 9999973

Sample Input

1 3

Sample Output

7

HINT

除了在3個格子中都放滿炮的的情況外,其它的都可以.

100%的數據中N,M不超過100
50%的數據中,N,M至少有一個數不超過8
30%的數據中,N,M均不超過6

看起來很像狀壓DP的套路是不是?然而只是個很水的比較基礎的DP。

滿足要求的方法:每行每列棋子數不超過2,就有6種放法。

(1) 不放;(2) 放一個棋子,在之前沒有棋子的一列;(3) 放一個棋子,在之前有棋子的一列;(4) 放兩個棋子,在之前沒有棋子的兩列;(5) 放兩個棋子,在之前沒有棋子的一列和在之前有棋子的一列;(6) 放兩個棋子,在之前有棋子的兩列。

f[i][j][k]表示前i行,有j列是一個棋子,有k列是兩個棋子的方案數,答案如左下

技術分享

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 const int mod=9999973;
 6 using namespace std;
 7 int n,m;
 8 long long ans;
 9 long long f[110][110][110];
10 int main(){
11     scanf("%d%d",&n,&m);
12     memset(f,0,sizeof(f));
13 f[0][0][0]=1; 14 for(int i=1;i<=n;i++) 15 for(int j=0;j<=m;j++) 16 for(int k=0;k<=m-j;k++){ 17 f[i][j][k]=f[i-1][j][k]; 18 if(j>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-j-k+1))%mod; 19 if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1))%mod; 20 if(j>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2)%mod; 21 if(k>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*(j+2)*(j+1)/2)%mod; 22 if(j>=1&&k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*(m-j-k+1)*j)%mod; 23 } 24 for(int i=0;i<=m;i++) 25 for(int j=0;j<=m-i;j++) ans=(ans+f[n][i][j])%mod; 26 printf("%lld\n",ans); 27 }

動態規劃 BZOJ1801 [Ahoi2009]chess 中國象棋