Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 1768 Solved: 1115
[Submit][Status][Discuss]
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
Source
第一輪Day2
簡單題意:求長度爲n的波動數列個數。
這就很有意思,自己想了好久,找不到其本質的東西。
波動數列有一些有趣的性質。
比如,對於51423這樣的波動數列,將數字全部“取反”,也就是對於x,變成n+1-x,變成65243,它仍然是一個波動數列,這就好像把sin的圖像乘-1一樣。
定義f[i][j]爲考慮了i個數,最後一個數第j大,且爲山谷的方案數。
類似地,定義g[i][j]爲考略了i個數,最後一個數第j大,且爲山峯的方案數。
由於上面說到的取反性質,可以寫出g[i][j]=f[i][i+1-j]。
爲什麼這裏是i+1-j而不是n+1-j呢?注意,定義的第j大是在考慮了的前i個數中的相對大小,我們不關心它是不是真的“j”這個數,同理,前i個數,也不一定是1到i的一個排列,而是任意的i個數。
同時,我們有f[i][j]=Σg[i-1][k]*[j<=k<=i-1]
爲什麼呢?要讓最後一個數加入成爲山谷,說明它小於前面的數,前面可以接受的最小數是多少呢?第一反應是j-1,但是注意這裏的j是相對排名,由於加入了新的數x,且x小於前面的數,所以前面的數排名就升了一位,也就是說前面最小是j,這就是轉移的下界,上界自然是前面的最大排名i-1。
由此,聯立二式可得
f[i][j]=Σg[i-1][k]*[j<=k<=i-1],
g[i-1][k]=f[i-1][i-k],
f[i][j]=Σg[i-1][k]=f[i-1][i-k] * [j<=k<=i-1]=f[i-1][k] * [j<=i-k<=i-1]=Σg[i-1][k]=f[i-1][k] * [1<=k<=i-j]
注意到這裏的f[i-1][k]的k的上界隨着i增大而增大,可以用變量儲存,O(1)轉移
#include<cstdio>
#include<cstring>
#include<iostream>
const int maxn=5005;
int n, p, f[2][maxn], s, ans;
int main(){
cin>>n>>p;
f[1][1] = 1;
for (int i=2; i<=n;i++) {
s=0;
for(int j=i-1;j;j--) {
s=(s+f[(i-1)&1][i-j])%p;
f[i&1][j]=s;
}
}
for(int j=1;j<=n;++j) {
ans=(ans+f[n&1][j])%p;
}
cout<<(ans<<1)%p;
return 0;
}