動態規劃 BZOJ1801 [Ahoi2009]chess 中國象棋
阿新 • • 發佈:2017-07-30
vtp size bom hint sizeof ecg 然而 cda 中國象棋
Submit: 1861 Solved: 1068
[Submit][Status][Discuss]
1801: [Ahoi2009]chess 中國象棋
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1861 Solved: 1068
[Submit][Status][Discuss]
Description
在N行M列的棋盤上,放若幹個炮可以是0個,使得沒有任何一個炮可以攻擊另一個炮。 請問有多少種放置方法,中國像棋中炮的行走方式大家應該很清楚吧.Input
一行包含兩個整數N,M,中間用空格分開.Output
輸出所有的方案數,由於值比較大,輸出其mod 9999973Sample Input
1 3Sample Output
7HINT
除了在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 中國象棋