博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[P1121]环状最大两段子段和
阅读量:4311 次
发布时间:2019-06-06

本文共 1315 字,大约阅读时间需要 4 分钟。

给定一个环状序列(\(a_1\)\(a_n\)相邻),求:连续不重叠且非空的两段使得这两段和最大

有两种情况:中间选两段或者用到环的左右部分,

一种思路是用线段树维护普通的最大子段和(而且要在中间),再加上环的左右两段;中间的两段可以把所有数负过来,就变成了求中间加左右的最小值,\(ans2=sum+query()\)
但是这样会有bug : 如果\(T.Max[1]==T.L[1]\)就无法处理了.

所以不能用线段树,这里用到DP:枚举以\(i\)为界,求左边最大值+右边最大值即可

还要特判:如果正数\(<=1\)个,则直接选出最大的两个数.

#include
#include
#include
#include
#define debug(...) fprintf(stderr,__VA_ARGS__)#define Debug(x) cout<<#x<<"="<
<
57){if(c=='-')f=-1;c=getchar();} while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar(); return f*x;}const int N=2e5+5;int a[N],l[N],r[N];int n,sum,cnt,ans1,ans2;inline int query(){ // 中间两段最大 int res=-INF; memset(l,0xcf,sizeof l); memset(r,0xcf,sizeof r); for(int i=1;i<=n;i++) l[i]=max(l[i-1],0)+a[i]; for(int i=1;i<=n;i++) l[i]=max(l[i-1],l[i]); for(int i=n;i>=1;i--) r[i]=max(r[i+1],0)+a[i]; for(int i=n;i>=1;i--) r[i]=max(r[i+1],r[i]); for(int i=1;i<=n-1;i++) res=max(res,l[i]+r[i+1]);//以i为界,左边最大值+右边最大值 return res;}int main(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(),sum+=a[i],cnt+=(a[i]>0); if(cnt<=1){ sort(a+1,a+n+1); printf("%d\n",a[n]+a[n-1]); return 0; } ans1=query(); for(int i=1;i<=n;i++) a[i]=-a[i]; ans2=sum+query(); printf("%d\n",max(ans1,ans2));}

转载于:https://www.cnblogs.com/lizehon/p/10914811.html

你可能感兴趣的文章
0909我对编译原理的见解
查看>>
lib 和 dll
查看>>
hdu 2042 - 不容易系列之二
查看>>
Linux下设置postgresql数据库开机启动
查看>>
mysql函数技巧整理
查看>>
二叉树
查看>>
IO多路复用--epoll详解
查看>>
[线段树优化应用] 数星星Star
查看>>
表单序列化以及后台表单数据参数的提取
查看>>
SQL语句(十五)视图
查看>>
nginx 设置开机启动
查看>>
继承和组合
查看>>
小程序-----上传图片
查看>>
工作流表单自定义的误区
查看>>
带有循环功能的存储过程
查看>>
数据结构-链表插入节点
查看>>
软件项目开发流程
查看>>
常用排序算法
查看>>
DOM(文档对象模型)
查看>>
为什么要安全域,哪些区域需要单独划分安全域
查看>>