Two Merged Sequences(CF 1144 G)

前言

在做其它题的时候脑补到过这个题意,没想到还真有这样的题

题目相关

链接

题目大意

给一个序列,问是否能将这个序列完全划分成一个上升子序列和下降子序列

数据范围

n≤2⋅105n\le2·10^5n2105

题解

有个不错的思路:
找到最大值,讨论他是上升序列的最后一个元素还是下降序列的第一个元素
如果是上升序列的最后一个元素,那么需要满足两个条件:
1.其后面的元素都是在下降序列中的
2.其前面的元素的下降序列中的最后一个元素大于后面的元素
如果这是下降序列的第一个元素,将数组翻转即可
我们发现,对于第一个条件的满足与否,就可以判断是哪种情况

  • 两边都不满足:无解
  • 有一边满足:可能是这种情况,转化子问题递归计算
  • 两边都满足:直接解决问题

递归计算时,我们发现有一个额外的限制,我们要先把这个限制弄掉
实际操作中,限制可以直接把连续的一段删除并产生新的限制,若新的限制无效了,那么就是子问题了,再递归计算即可
以上的做法可能要用到线段树,并且要在线段树上二分之类的,不是很好写
而且复杂度为O(nlogn)\mathcal O(nlogn)O(nlogn)


然后,这里隆重推出O(n)\mathcal O(n)O(n)的dp做法
看来是我dp没学好,咋开始没想到呢?
我们定义状态:
fi,0f_{i,0}fi,0为第iii个数在下降子序列上,此时上升子序列最大值的最小值
fi,1f_{i,1}fi,1为第iii个数在上升子序列上,此时下降子序列最小值的最大值
转移的话直接讨论一下上个状态和下个状态放哪种就好了
然后就可以直接判定
输出方案的话记录每一个状态的前继状态即可
清真+好写+复杂度低

代码

#include
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;
}

总结

挺巧妙的一道题
有时候换种做法说不定会好写很多


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部