【GDOI模拟】奇妙的数列
2016-04-10 00:08
225 查看
Description
Solution
题意就是要求最长的一段区间,中间的最小值不比左端点小,中间的最大值不比右端点大。第一眼可以用线段树
维护最大值和最小值。时间复杂度O(n(logn)2)
第二眼就想到O(n)
对于i来说因为只用找右边第一个比a[i]小的数,和左边第一个比a[i]大的数,就可以了。维护这两个值O(n)用f和g数组预处理一下就好了。
f[i]表示右边第一个比a[i]小的数的左边那个数。
g[i]表示左边第一个比a[i]大的数的右边那个数。
如果找出了边界,就存边界就好了。
然后很明显,对于i来说,i到f[i]这段区间是合法的,因为这些数都不小于他。那么我们只用再在这个区间内找一个数j,他的g[j]是不大于i的就好了,这说明g[j]到j这段区间的数都不大于a[j],然后再要求j最大,到这用g一直跳到覆盖i为止就好了。
因为每个数只会被比较一次,所以时间复杂度O(n)
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define fo(i,a,b) for(i=a;i<=b;i++) #define fod(i,a,b) for(i=a;i>=b;i--) using namespace std; const int maxn=10000007; inline int read(){ char ch=getchar(); int data=0; while(ch<'0'||ch>'9'){ ch=getchar(); } do{ data=data*10+ch-'0'; ch=getchar(); }while(ch>='0'&&ch<='9'); return data; } int i,j,k,l,t,n,m,ans,f[maxn],g[maxn]; int a[maxn]; int main(){ n=read(); fo(i,1,n){ a[i]=read(); } fod(i,n,1){ f[i]=i; while(f[i]+1<=n&&a[f[i]+1]>=a[i])f[i]=f[f[i]+1]; } fo(i,1,n){ g[i]=i; while(g[i]-1>=1&&a[g[i]-1]<=a[i])g[i]=g[g[i]-1]; } fo(i,1,n){ t=f[i]; while(g[t]>i)t=g[t]-1; ans=max(t-i+1,ans); } printf("%d\n",ans); }
相关文章推荐
- java socket 文件上传 有文件名
- [前端 3]纯Js制作俄罗斯方块游戏
- 文章标题
- 判断两矩形是否相交
- [前端 3]纯Js制作俄罗斯方块游戏
- iOS开发证书,描述文件,bundle ID的关系
- servlet 学习(二)
- PowerDesigner(八)-面向对象模型(用例图,序列图,类图,生成Java源代码及Java源代码生成类图)面向对象模型 面向对象模型是利用UML(统一建模语言)的图形来描述系统结构的模型,
- 项目管理之——如何优雅的做好离职交接工作?
- AngularJS简单的数据绑定
- 关于对clientX(Y)/pageX(Y)/screenX(Y)的认识
- 【CodeForces】[1B]Spreadsheet
- linux查看系统启动时间
- eclipse安装中文语言包
- 触发器记录对表记录操作
- 结对项目编程-四则运算
- 从零开始创建iOS远程推送证书
- 关于js封装框架类库之选择器引擎(一)
- D3实现简单业务拓扑图
- AngularJS 中的数据绑定