「Solution」華一高ks10.5 T1 & P1970 花匠
阿新 • • 發佈:2020-10-05
思路和洛谷第一篇題解類似,但是第一篇題解是能夠被hack的,hack資料:
1
1
題解輸出2
,答案1
。
這裡給出更完善的寫法。
首先,回顧一下求非降子序列的寫法:
int a[MAXN], d[MAXN]; int dp() { d[1] = 1; int ans = 1; for (int i = 2; i <= n; i++) { for (int j = 1; j < i; j++) if (a[j] <= a[i]) { d[i] = max(d[i], d[j] + 1); ans = max(ans, d[i]); } } return ans; }
\(O(n^2)\) From OI Wiki
考場上,我就是按照非降子序列的思路AC了這道題。
AC Code
#include<bits/stdc++.h> //#define debug // 除錯開關 using namespace std; int h[100005], dp[2][100005], f1 = 1, f2 = -1, n; int cmp(int a, int b){ if(a > b) return 1; else if (a < b) return -1; else return 0; } int main(){ // freopen("flower.in", "r", stdin); // freopen("flower.out", "w", stdout); cin >> n; for(int i = 0; i < n; i++) cin >> h[i]; dp[0][0] = dp[1][0] = 1; for(int i = 1; i < n; i++){ dp[0][i] = dp[0][i-1]; dp[1][i] = dp[1][i-1]; if(cmp(h[i], h[i-1]) == f1) dp[0][i]++, f1 *= -1; if(cmp(h[i], h[i-1]) == f2) dp[1][i]++, f2 *= -1; } #ifdef debug for(int i = 0; i < n; i++) cout << dp[0][i] << " "; cout << endl; for(int i = 0; i < n; i++) cout << dp[1][i] << " "; cout << endl; #endif cout << max(dp[0][n-1], dp[1][n-1]); return 0; }
解題方法
常規來講,這個部分應該放在程式碼前面,但是對於這麼一道題,我認為先看程式碼再看講解會更好。
兩個dp
同時進行,dp[0]
考慮輸入資料中滿足條件\(A\)的最長序列,dp[1]
則考慮條件\(B\),輸出時比較兩者最終結果取較大者即可。
cmp
函式是為了方便做比較。
f1
和f2
陣列分別是dp[0]
和dp[1]
的flag
,代表序列\(g\)的下一個元素相比與末尾元素應該更大還是更小。
讀懂程式碼應該沒有什麼難度,那麼接下來,我們注意到,非降子序列複雜度是\(O(n^2)\),而上面的程式碼雖然思路和非降子序列一樣,但複雜度是線性的,那麼,我們來證明以上演算法的正確性。
對於非降子序列,如果有\(a_1 \leq a_2 \leq ··· \leq a_n\)
而對於本題而言,如果有\(a_{n-1} < a_n\)(或\(a_{n-1} > a_n\),這裡只考慮一種情況),並且有\(a_n \leq a_{n+1} \leq a_{n+2} \leq ··· \leq a_{i-1}, \space a_i > a_{i-1}(i > n+1)\),顯然聯立兩式,便有\(a_i > a_n\),所以我們線性的做法是正確的。
大水題