[BZOJ] 1925 [Sdoi2010]地精部落

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1768  Solved: 1115
[Submit][Status][Discuss]
Description
傳說很久以前,大地上居住着一種神祕的生物:地精。 地精喜歡住在連綿不絕的山脈中。具體地說,一座長度爲 N 的山脈 H可分 爲從左到右的 N 段,每段有一個獨一無二的高度 Hi,其中Hi是1N 之間的正 整數。 如果一段山脈比所有與它相鄰的山脈都高,則這段山脈是一個山峯。位於邊 緣的山脈只有一段相鄰的山脈,其他都有兩段(即左邊和右邊)。 類似地,如果一段山脈比所有它相鄰的山脈都低,則這段山脈是一個山谷。 地精們有一個共同的愛好——飲酒,酒館可以設立在山谷之中。地精的酒館 不論白天黑夜總是人聲鼎沸,地精美酒的香味可以飄到方圓數裏的地方。 地精還是一種非常警覺的生物,他們在每座山峯上都可以設立瞭望臺,並輪 流擔當瞭望工作,以確保在第一時間得知外敵的入侵。 地精們希望這N 段山脈每段都可以修建瞭望臺或酒館的其中之一,只有滿足 這個條件的整座山脈纔可能有地精居住。 現在你希望知道,長度爲N 的可能有地精居住的山脈有多少種。兩座山脈A 和B不同當且僅當存在一個 i,使得 Ai≠Bi。由於這個數目可能很大,你只對它 除以P的餘數感興趣。
Input
僅含一行,兩個正整數 N, P。
Output
僅含一行,一個非負整數,表示你所求的答案對P取餘 之後的結果。
Sample Input
4 7
Sample Output
3
HINT


對於 20%的數據,滿足 N10; 
對於 40%的數據,滿足 N18; 
對於 70%的數據,滿足 N550; 
對於 100%的數據,滿足 3N4200,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;
}
發佈了180 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章