1. 程式人生 > >Luogu2467 SDOI2010 地精部落 DP

Luogu2467 SDOI2010 地精部落 DP

傳送門


 

一個與相對大小關係相關的$DP$

設$f_{i,j,0/1}$表示放了$i$個,其中最後一個數字在$i$箇中是第$j$大,且最後一個是極大值($1$)或極小值時($0$)的方案數。轉移:

$$f_{i+1,j,1}=\sum\limits_{k=1}^{j-1} f_{i,k,0},f_{i+1,j,0} = \sum\limits_{k=j}^{i} f_{i,k,1}$$

發現轉移可以字首和優化,優化後複雜度為$O(n^2)$可以通過此題。

 1 #include<bits/stdc++.h>
 2 //This code is written by Itst
3 using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 bool f = 0; 8 char c = getchar(); 9 while(c != EOF && !isdigit(c)){ 10 if(c == '-') 11 f = 1; 12 c = getchar(); 13 } 14 while(c != EOF && isdigit(c)){ 15 a = (a << 3
) + (a << 1) + (c ^ '0'); 16 c = getchar(); 17 } 18 return f ? -a : a; 19 } 20 21 const int MAXN = 4210; 22 int MOD , N , dp[MAXN][MAXN][2]; 23 24 int main(){ 25 #ifndef ONLINE_JUDGE 26 freopen("2467.in" , "r" , stdin); 27 //freopen("2467.out" , "w" , stdout); 28 #endif 29
N = read(); 30 MOD = read(); 31 dp[1][1][0] = dp[1][1][1] = 1; 32 for(int i = 2 ; i <= N ; ++i){ 33 for(int j = 1 ; j <= i ; ++j){ 34 dp[i][j][0] = dp[i - 1][j][1]; 35 dp[i][j][1] = dp[i - 1][j - 1][0]; 36 } 37 for(int j = 1 ; j <= i ; ++j) 38 dp[i][j][0] = (dp[i][j][0] + dp[i][j - 1][0]) % MOD; 39 for(int j = i ; j ; --j) 40 dp[i][j][1] = (dp[i][j][1] + dp[i][j + 1][1]) % MOD; 41 } 42 cout << (dp[N][N][0] + dp[N][1][1]) % MOD; 43 return 0; 44 }