Two Merged Sequences(CF 1144 G)
前言
在做其它題的時候腦補到過這個題意,沒想到還真有這樣的題
題目相關
鏈接
題目大意
給一個序列,問是否能將這個序列完全劃分成一個上升子序列和下降子序列
數據范圍
n≤2?105n\le2·10^5n≤2?105
題解
有個不錯的思路:
找到最大值,討論他是上升序列的最后一個元素還是下降序列的第一個元素
如果是上升序列的最后一個元素,那么需要滿足兩個條件:
1.其后面的元素都是在下降序列中的
2.其前面的元素的下降序列中的最后一個元素大于后面的元素
如果這是下降序列的第一個元素,將數組翻轉即可
我們發(fā)現,對于第一個條件的滿足與否,就可以判斷是哪種情況
- 兩邊都不滿足:無解
- 有一邊滿足:可能是這種情況,轉化子問題遞歸計算
- 兩邊都滿足:直接解決問題
遞歸計算時,我們發(fā)現有一個額外的限制,我們要先把這個限制弄掉
實際操作中,限制可以直接把連續(xù)的一段刪除并產生新的限制,若新的限制無效了,那么就是子問題了,再遞歸計算即可
以上的做法可能要用到線段樹,并且要在線段樹上二分之類的,不是很好寫
而且復雜度為O(nlogn)\mathcal O(nlogn)O(nlogn)
然后,這里隆重推出O(n)\mathcal O(n)O(n)的dp做法
看來是我dp沒學好,咋開始沒想到呢?
我們定義狀態(tài):
fi,0f_{i,0}fi,0?為第iii個數在下降子序列上,此時上升子序列最大值的最小值
fi,1f_{i,1}fi,1?為第iii個數在上升子序列上,此時下降子序列最小值的最大值
轉移的話直接討論一下上個狀態(tài)和下個狀態(tài)放哪種就好了
然后就可以直接判定
輸出方案的話記錄每一個狀態(tài)的前繼狀態(tài)即可
清真+好寫+復雜度低
代碼
#include<bits/stdc++.h> typedef long long ll; #define rg register template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;} template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');} template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);} template <typename T> inline T min(const T a,const T b){return a<b?a:b;} template <typename T> inline T max(const T a,const T b){return a>b?a:b;} const int inf=0x7f7f7f7f; int n,a[200001],opt[200001]; int f[200001][2],g[200001][2]; int main() {read(n);for(rg int i=1;i<=n;i++)read(a[i]);f[1][0]=-inf,f[1][1]=inf;for(rg int i=2;i<=n;i++){f[i][0]=inf,f[i][1]=-inf;if(a[i-1]>a[i]&&f[i][0]>f[i-1][0]){f[i][0]=f[i-1][0];g[i][0]=0;}if(f[i-1][0]<a[i]&&f[i][1]<a[i-1]){f[i][1]=a[i-1];g[i][1]=0;}if(a[i-1]<a[i]&&f[i][1]<f[i-1][1]){f[i][1]=f[i-1][1];g[i][1]=1;}if(f[i-1][1]>a[i]&&f[i][0]>a[i-1]){f[i][0]=a[i-1];g[i][0]=1;}}if(f[n][0]!=inf){puts("YES");for(rg int i=n,op=0;i>=1;op=g[i][op],i--)opt[i]=op;for(rg int i=1;i<=n;i++)print(opt[i]^1),putchar(' ');return 0;}if(f[n][1]!=-inf){puts("YES");for(rg int i=n,op=1;i>=1;op=g[i][op],i--)opt[i]=op;for(rg int i=1;i<=n;i++)print(opt[i]^1),putchar(' ');return 0;}puts("NO");return 0; }總結
挺巧妙的一道題
有時候換種做法說不定會好寫很多
總結
以上是生活随笔為你收集整理的Two Merged Sequences(CF 1144 G)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [loj3056][hnoi2019]多
- 下一篇: codeforces contest 1