HDOJ 4604 - Deque O(nlogn)的最长非升(非降)

网友投稿 240 2022-11-06


HDOJ 4604 - Deque O(nlogn)的最长非升(非降)

4 3 2 1 5 : (4),(3 4),(2 3 4),(1 2 3 4),(1 2 3 4 5)

3 4 2 5 1 :(3),(3 4),(2 3 4),(2 3 4 5),(1 2 3 4 5)

可见需要找的是一个非降序列和非升序列..他们没有重合的部分..长度之和最大...因为对于非降的..从右进..非升的从左进..又保证了不重合..那么必定从右进的所有数大于等于从左进的所有数...

由于题目没有给出每个数的大小...先离散化..确定每个数在数列中是第几大....找最长非降和最长非升必须用O(nlogn)的算法...这个算法不在累述...在找每个数的最长非升和非降的时候跟新离散化的这个数的最长非降和最长非升..最后..找到每个数k的最长非降+(k~n)的最长非升最大值..这个过程可以O(n)完成..

比如  4 3 2 1 5 ....L[0]记录每个数的长非降..L[1]记录每个数的最长非升...都是从后往前...不如把原数列反过来看..5 1 2 3 4

原值  1  2  3  4  5

离散化后值的顺序  1  2  3  4  5

L[0]   1  2  3  4  1

L[1]   2  2  2  2  1        这其中L[0][i]+max(L[1][k]) < k>i > 的最大值有L[0][3]+L[1][4]=5,L[0][4]+L[1][5]..也就是< (3,2,1),(4,5)>与<(4,3,2,1),(5)>

又比如说3 3 3 3 4 4 3 3  反过来看 3 3 4 4 3 3 3 3...原数列只有两个数值..离散化后就只有两个值了...

原值   3  4

离散化后值的顺序   1  2

L[0]    6  4

L[1]    6  2                   这其中L[0][i]+max(L[1][k]) < k>i > 的最大值有L[0][1]+L[1][2]=8,也就是<(3,3,3,3,3,3),(4,4)>

最后一个问题..如果已经得到了L[0],L[1]..如何在O(n)的时间内找出L[0][i]+max(L[1][k]) < k>i >的最大值.

对于每个L[0][i]每次要找的是max(L[1][k]) < k>i >,那么不妨将扫描顺序从i最大开始..边更新答案..边更新最长的可用非升...

最后统计时不这么做..用个线段树来维护也行(找区间最大值).我开始是用线段树维护的..写崩了..但一定是可行的...

Program:

#include#include#include#include#include#include#include#define ll long long#define oo 1000000007#define MAXN 100010using namespace std;int n,a[MAXN],num,X[MAXN],b[MAXN],M[MAXN],L[2][MAXN],H[2][MAXN],m[2]; int turn(int x){ int l,r,mid; l=0,r=num+1; while (r-l>1) { mid=(l+r)>>1; if (X[mid]<=x) l=mid; else r=mid; } return l;}void find1(){ int i,l,r,mid,x; m[0]=0; for (i=n;i>=1;i--) { x=a[i]; l=0; r=m[0]+1; while (r-l>1) { mid=(l+r)>>1; if (H[0][mid]<=x) l=mid; else r=mid; } if (r>m[0]) m[0]=r,H[0][r]=a[i]; else H[0][r]=min(H[0][r],a[i]); x=turn(x); L[0][x]=max(L[0][x],r); } return;}void find2(){ int i,l,r,mid,x; m[1]=0; for (i=n;i>=1;i--) { x=a[i]; l=0; r=m[1]+1; while (r-l>1) { mid=(l+r)>>1; if (H[1][mid]>=x) l=mid; else r=mid; } if (r>m[1]) m[1]=r,H[1][r]=a[i]; else H[1][r]=max(H[1][r],a[i]); x=turn(x); L[1][x]=max(L[1][x],r); } return;} int main(){ int Case,i,ans,MM; scanf("%d",&Case); while (Case--) { scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+1+n),b[0]=-oo,num=0; for (i=1;i<=n;i++) if (b[i]!=b[i-1]) X[++num]=b[i]; // 由于不知道每个数的范围..相当于离散化了. memset(L,0,sizeof(L)); find1(); find2(); ans=MM=0; for (i=num;i>=1;i--) { ans=max(ans,L[0][i]+MM); MM=max(MM,L[1][i]); //更新可用的最长非升 } printf("%d\n",ans); } return 0;}/*571 2 3 4 5 6 754 3 2 1 555 4 1 2 383 3 3 3 4 4 3 351 1 1 1 1 */


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:在Spring 中使用@Aspect 控制自定义注解的操作
下一篇:京东快递查询单号查询API(京东快递查询单号查询 快递单号)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~