1. 程式人生 > 實用技巧 >「Solution」華一高ks10.5 T1 & P1970 花匠

「Solution」華一高ks10.5 T1 & P1970 花匠

思路和洛谷第一篇題解類似,但是第一篇題解是能夠被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函式是為了方便做比較。

f1f2陣列分別是dp[0]dp[1]flag,代表序列\(g\)的下一個元素相比與末尾元素應該更大還是更小。

讀懂程式碼應該沒有什麼難度,那麼接下來,我們注意到,非降子序列複雜度是\(O(n^2)\),而上面的程式碼雖然思路和非降子序列一樣,但複雜度是線性的,那麼,我們來證明以上演算法的正確性。

對於非降子序列,如果有\(a_1 \leq a_2 \leq ··· \leq a_n\)

,並且有\(a_{i-1} < a_n , \space a_i \geq a_{i-1}(i > n+1)\),顯然並不能保證\(a_i \geq 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\),所以我們線性的做法是正確的。

大水題