1. 程式人生 > >BZOJ1925:[SDOI2010]地精部落(DP)

BZOJ1925:[SDOI2010]地精部落(DP)

Description

傳說很久以前,大地上居住著一種神祕的生物:地精。 地精喜歡住在連綿不絕的山脈中。具體地說,一座長度為 N 的山脈 H可分 為從左到右的 N 段,每段有一個獨一無二的高度 Hi,其中Hi是1到N 之間的正 整數。 如果一段山脈比所有與它相鄰的山脈都高,則這段山脈是一個山峰。位於邊 緣的山脈只有一段相鄰的山脈,其他都有兩段(即左邊和右邊)。 類似地,如果一段山脈比所有它相鄰的山脈都低,則這段山脈是一個山谷。 地精們有一個共同的愛好——飲酒,酒館可以設立在山谷之中。地精的酒館 不論白天黑夜總是人聲鼎沸,地精美酒的香味可以飄到方圓數裡的地方。 地精還是一種非常警覺的生物,他們在每座山峰上都可以設立瞭望臺,並輪 流擔當瞭望工作,以確保在第一時間得知外敵的入侵。 地精們希望這N 段山脈每段都可以修建瞭望臺或酒館的其中之一,只有滿足 這個條件的整座山脈才可能有地精居住。 現在你希望知道,長度為N 的可能有地精居住的山脈有多少種。兩座山脈A 和B不同當且僅當存在一個 i,使得 Ai≠Bi。由於這個數目可能很大,你只對它 除以P的餘數感興趣。

Input

僅含一行,兩個正整數 N, P。

Output

僅含一行,一個非負整數,表示你所求的答案對P取餘 之後的結果。

Sample Input

4 7

Sample Output

3

HINT



對於 20%的資料,滿足 N≤10;
對於 40%的資料,滿足 N≤18;
對於 70%的資料,滿足 N≤550;
對於 100%的資料,滿足 3≤N≤4200,P≤109

Solution

首先可以發現這個序列的特點就是折來折去的,這玩意兒叫波動數列,它有一個性質叫對稱性。

假如$n=5$的一個波動數列為$5,2,4,1,3$,那麼他對稱的序列就是$1,4,2,5,3$,可以發現原序列的對稱數列也是一個波動數列。

那麼我們設$f[i][j]$表示前$i$個數構成的排列第一個數的取值範圍為$[1,j]$且第一個數為山峰的方案數。

首先很顯然,若第一個數為$[1,j-1]$則$f[i][j]+=f[i][j-1]$。

若第一個數為$j$,剩下$i-1$個數離散一下就是一個大小為$i-1$的數集,且這個數集開頭必須選$[1,j-1]$,但是$f$陣列記錄的是第一個數為山峰的值,這個時候就可以根據上面提到的對稱性轉化成$f[i][j]+=f[i-1][i-j]$

Code

 1 #include<cstdio>
 2 #define N (4209)
 3 int n,p,f[2
][N]; 4 int main() 5 { 6 scanf("%d%d",&n,&p); 7 f[1][1]=1; 8 for (int i=2; i<=n; ++i) 9 for (int j=1; j<=i; ++j) 10 f[i&1][j]=(f[i&1][j-1]+f[(i-1)&1][i-j])%p; 11 printf("%d\n",f[n&1][n]*2%p); 12 }