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