1. 程式人生 > >[SDOI2010]地精部落

[SDOI2010]地精部落

一個點 邊緣 山谷 個數 得到 spa long long -m for

傳說很久以前,大地上居住著一種神秘的生物:地精。

地精喜歡住在連綿不絕的山脈中。具體地說,一座長度為N的山脈H可分為從左到右的N段,每段有一個獨一無二的高度Hi,其中Hi是1到N之間的正整數。

如果一段山脈比所有與它相鄰的山脈都高,則這段山脈是一個山峰。位於邊緣的山脈只有一段相鄰的山脈,其他都有兩段(即左邊和右邊)。

類似地,如果一段山脈比所有它相鄰的山脈都低,則這段山脈是一個山谷。

地精們有一個共同的愛好——飲酒,酒館可以設立在山谷之中。地精的酒館不論白天黑夜總是人聲鼎沸,地精美酒的香味可以飄到方圓數裏的地方。

地精還是一種非常警覺的生物,他們在每座山峰上都可以設立瞭望臺,並輪流擔當瞭望工作,以確保在第一時間得知外敵的入侵。

地精們希望這N段山脈每段都可以修建瞭望臺或酒館的其中之一,只有滿足這個條件的整座山脈才可能有地精居住。

現在你希望知道,長度為N的可能有地精居住的山脈有多少種。兩座山脈A和B不同當且僅當存在一個i,使得Ai≠Bi。由於這個數目可能很大,你只對它除以P的余數感興趣。

輸入輸出格式

輸入格式:

輸入文件goblin.in僅含一行,兩個正整數N, P。

輸出格式:

輸出文件goblin.out僅含一行,一個非負整數,表示你所求的答案對P取余之後的結果。

輸入輸出樣例

輸入樣例#1:
4 7
輸出樣例#1:
3

說明

說明:共有10種可能的山脈,它們是:

1[u]3[/u]2[u]4[/u] 1[u]4[/u]2[u]3[/u] [u]2[/u]1[u]4[/u]3 2[u]3[/u]1[u]4[/u] 2[u]4[/u]1[u]3[/u]

[u]3[/u]1[u]4[/u]2 [u]3[/u]2[u]4[/u]1 3[u]4[/u]1[u]2[/u] [u]4[/u]1[u]3[/u]2 [u]4[/u]2[u]3[/u]1

其中加下劃線的數位表示可以設立瞭望臺的山峰,其他表示可以設立酒館的山谷。

【數據規模和約定】

對於20%的數據,滿足N≤10;

對於40%的數據,滿足N≤18;

對於70%的數據,滿足N≤550;

對於100%的數據,滿足3≤N≤4200,P≤1e9。

就是要求長度為n的排列的擺動數列的數量.
有三個引理
1、在n->n-1的轉化過程中,我們刪除了一個點後,我們可以將n-1個點視為仍是1~n-1的排列。
證明:假設把j刪除了,那麽將j以後的都-1,那麽就是一個1-(j-1)的排列.
2、若排列Pn為一個合法抖動子序列,則交換i∈[1,n)i+1,必能得到另一個抖動子序列(ii+1不相鄰)
證明:手玩即可.
3、抖動序列的對稱性,若存在第一段上升的長度為n的抖動子序列,則以n+1-xx必能得到一個第一段下降的長度為n的抖動子序列。
證明:顯然.
f[i][j]表示長度為i的排列,這個排列的第一個數為j,且第一段下降的方案數.
1.jj-1不相鄰,那麽根據引理2,f[i][j]+=f[i][j-1].因為第一段下降所以第二個數不可能是j,所以j-1j不相鄰.
2.jj-1相鄰,那麽j的前面就是j-1,根據對稱性,f[i][j]+=f[i-1][i-1-(j-1)+1]f[i][j]+=f[i-1][i-j+1].
 1 #include<bits/stdc++.h>
 2 #define maxn 5000
 3 #define LL long long
 4 using namespace std;
 5 int n,mod;
 6 LL ans=0,f[2][maxn];
 7 int main(){
 8   scanf("%d%d",&n,&mod);
 9   int t=0,tt=1;
10   f[0][1]=1;
11   for(int i=2;i<=n;i++){
12     swap(t,tt);
13     for(int j=1;j<=i;j++)
14       f[t][j]=(f[t][j-1]+f[tt][i-j+1])%mod;
15   }
16   for(int i=1;i<=n;i++) ans+=f[t][i],ans%=mod;
17   printf("%lld",(ans*2)%mod);
18   return 0;
19 }

[SDOI2010]地精部落