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

[Codevs] 1523 地精部落

one 等級 第一個 分類 16px splay center mas 滿足

1523 地精部落

省隊選拔賽

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

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

輸出描述 Output Description

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

樣例輸入 Sample Input

4 7

樣例輸出 Sample Output

3

數據範圍及提示 Data Size & Hint

共有10 種可能的山脈,它們是:
1324 1423 2143 2314 2413
3142 3241 3412 4132 4231

【數據規模和約定】
對於 20%的數據,滿足 N≤10;
對於 40%的數據,滿足 N≤18;
對於 70%的數據,滿足 N≤550;
對於 100%的數據,滿足 3≤N≤4200,P≤109

分析 Analysis

我相信這道題一定有組合數學的解法(然而我自己找不到)

主流解法動態規劃。

首先用DP[i][j]

表示一種狀態的方案數,該狀態的數集有i個數(可以意淫為1~i),其中該狀態子序列的第一個數取值範圍為1~j

PS:這麽意淫的前提是題目明確說明山峰高度是1~n的排列,因此顯然1~(j-1)均小於j

同時約定表示所代表的方案均為A1 < A2也就是開頭呈上升趨勢,因此有DP[i][j] = DP[i][j-1]+DP[i-1][i-j]

DP[i][j-1]表示同樣的狀態下序列中第一個數取值範圍為1~(j-1)時的方案數

DP[i-1][i-j]表示取走一個數之後的狀態,此時數集中只剩i-1個數,而此時序列的第二個數範圍必為j+1 ~ i,共i-j個數(因為已經約定序列開頭上升了,所以第二個數必須比j大)

PS:我寫這篇博客唯一的目的就是好好解釋清楚這個轉移方程

代碼 Code

技術分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 int dp[5000][5000];
 7 
 8 int main(){
 9     
10     int n;
11     scanf("%d",&n);
12     
13     dp[1][1] = 1;
14     for(int i = 2;i <= n;i++){
15         for(int j = 1;j <= i;j++){
16             dp[i][j] = dp[i][j-1]+dp[i-1][i-j];
17         }
18     }
19     
20     printf("%d",dp[n][n]);
21     
22     return 0;
23 }
推薦不看

評價&分類 Rank&Sort

思維題. >> 動態規劃

[Codevs] 1523 地精部落