acwing 1014. 登山| 最長“上升再下降”的子序列
阿新 • • 發佈:2022-03-13
目錄
題目描述
五一到了,ACM隊組織大家去登山觀光,隊員們發現山上一共有N個景點,並且決定按照順序來瀏覽這些景點,即每次所瀏覽景點的編號都要大於前一個瀏覽景點的編號。
同時隊員們還有另一個登山習慣,就是不連續瀏覽海拔相同的兩個景點,並且一旦開始下山,就不再向上走了。
隊員們希望在滿足上面條件的同時,儘可能多的瀏覽景點,你能幫他們找出最多可能瀏覽的景點數麼?
輸入格式
第一行包含整數N,表示景點數量。
第二行包含N個整數,表示每個景點的海拔。
輸出格式
輸出一個整數,表示最多能瀏覽的景點數。
資料範圍
2≤N≤10002≤N≤1000
輸入樣例:
8 186 186 150 200 160 130 197 220
輸出樣例:
4
最長上升子序列
分析
這個題目的題意不是很好理解
其實就是讓求得:先上升,後下降的最長子序列的長度
所以我們分兩個部分來求,對於每個點a[i]
- 首先求該點到左端點的最長下降子序列的長度
f[i]
:也就是從左端點到a[i]
的最長上升子序列的長度 - 然後求該點到右端點的最長下降子序列的長度
g[i]
:也就是從右端點到a[i]
的最長上升子序列長度- 注意求
g[i]
的時候需要逆序求,它不等於 左端點到該點的最長上升子序列的長度
- 注意求
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1010; int a[N]; int g[N], f[N]; int k, n; int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1; i <= n; i++) { f[i] = 1; for(int j = 1; j < i; j++) { if(a[j] < a[i]) f[i] = max(f[i], f[j] + 1); // 從左端點開始到a[i]的最長上升序列長度 } } for(int i = n; i >= 1; i--) { g[i] = 1; for(int j = n; j > i; j--) { if(a[i] > a[j]) g[i] = max(g[i], g[j] + 1); // 從a[i]開始到右端點的最長下降序列長度 // 也就是從右端點到a[i]的最長上升序列程度 } } // 注意上面的g[i]不能寫成這個形式: // 因為這個的g[i]表示的含義是從左邊端點到a[i]的最長下降子序列長度 // 並不是我們要的"a[i]開始到右端點的最長下降序列長度" /*for(int i = 1; i <= n; i ++){ g[i] = 1; for(int j = 1; j < i; j ++){ if(a[i] > a[j]) g[i] = max(g[i], g[j] + 1); } }*/ int res = 0; for(int i = 1; i <= n; i++) { res = max(res, f[i] + g[i] - 1); } printf("%d\n", res); return 0; }
時間複雜度
參考文章
https://www.acwing.com/problem/content/discussion/content/3331/