單調序列 解題報告
阿新 • • 發佈:2018-11-02
單調序列
\(\tt{GISPZJZ}\) 有一個長度為 \(n\) 的序列 \(a_1,a_2,\dots,a_n\)。 序列的所有元素都是 \(1\) 或者 \(2\)。
我們稱一序列是該序列的不下降子序列 \(p_1,p_2,\dots,p_k\), 滿足 \(1\le p_1<p_2<p_3<\dots <p_k\le n\), 且\(a_{p_1}\le a_{p_2}\le \dots \le a_{p_n}\)。
現在 \(\tt{GISPZJZ}\) 可以選擇序列中的一段區間\([L,R]\), 然後將整段反轉, 例如挑選區間\([2,4]\),可以將序列\((a_1,a_2,a_3,a_4,a_5)\)
輸入:
第一行一個正整數 \(n\)。
第二行 \(n\) 個數, 分別為 \(a_1,a_2,\dots,a_n\), 滿足 \(1\le a_i\le 2\)。
輸出:
一行一個正整數 \(x\), 表示答案。
資料範圍:
對於\(10\%\)的資料, \(1\le n\le 10\)。
對於\(40\%\)
對於\(70\%\)的資料, \(1\le n \le 2000\)。
對於\(100\%\)的資料, \(1\le n\le 100000\)。
思路還是很巧妙的。
最開始想把一串的縮在一起做,發現討論起來非常麻煩。
觀察了一下發現翻轉後不就是把\(000111\)什麼的變成了可以選\(000111000111\)這樣類似的了嗎?
於是直接劃分一下狀態\(\tt{DP}\)即可,是一個非常好的思路啊。
Code:
#include <cstdio> const int N=1e5+10; int a[N],dp[N][4],n,ans; int max(int x,int y){return x>y?x:y;} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",a+i),--a[i]; for(int i=1;i<=n;i++) { dp[i][0]=dp[i-1][0]+(a[i]==0); dp[i][1]=max(dp[i-1][0],dp[i-1][1])+(a[i]==1); dp[i][2]=max(dp[i-1][1],dp[i-1][2])+(a[i]==0); dp[i][3]=max(dp[i-1][2],dp[i-1][3])+(a[i]==1); ans=max(max(dp[i][0],dp[i][1]),max(dp[i][2],dp[i][3])); } printf("%d\n",ans); return 0; }
2017.11.2