博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
icpc 南昌邀请赛网络赛 Max answer
阅读量:4960 次
发布时间:2019-06-12

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

就是求区间和与区间最小值的积的最大值 但是a[i]可能是负的 这就很坑 赛后看了好多dalao的博客 终于a了

这个问题我感觉可以分为两个步骤

第一步是对于每个元素 以它为最小值的最大区间是什么

第二步是找出来在这个区间里面 最大的连续和多少

那么我们怎么找到第一步这个最大区间呢

可以先找这个元素左边第一个比他小的值的下标 和右边第一个比他小的值的下标 这两个下标确定了 最大区间就确定了

怎么找这个下标呢 暴力的话时间复杂度太高 是n^2 需要使用单调栈:

单调栈 顾名思义就是元素都是单调递增或者递减的栈 至于它有什么作用 接着往下看

假如有一个数组a:   3 5 1 6 2

用数组 L 表示a数组里的每一个元素 从自身位置 向左 第一个比它小的元素的位置

那么L就应该是: 0 1 0 3 3 (这里为了方便表示 我让a数组的下标从1开始标记 这样L数组里面 0 就表示左边的数都比他大 1 就表示第一个数比他小 以此类推)

那么我们怎么利用单调栈实现呢?

先将 a[0]赋值为一个极小值 -0x7ffffff,然后将0入栈

对于数组a的每一个元素 进行如下语句:

while(a[S.top()]>=a[i])         S.pop();      l[i] = S.top();S.push(i);

while语句 保证了栈里面的数据是单调递减的

看不明白没有关系 让我们模拟一下:

i==1时 a[S.top]=a[0]=-0x7ffffff 不进入while循环

所以L[1]=0;

将1入栈 此时的栈:0 1(实际上我们比较的是a[i] 所以逻辑上来讲 此时的栈:a[0] a[1] 也就是 -0x7ffff 3 因为我们需要用到左边的下标值 所以是将下标入栈 这样既可以访问到下标所对应的值 也可以访问下标)

i==2时,a[S.top]=a[1]=3 小于5 还是不进入while循环

L[2]=S.top()=1

将2入栈 此时的栈:0 1 2(-0x7ffff  3  5 )

i==3时,a[S.top]=a[2]=5 大于1

S.pop(),a[S.top]=a[1]=3还是大于1

S.pop(),a[S.top]=a[0]=-0x7ffffff 小于1 结束循环

所以L[3]=0

将3入栈 此时的栈:0 3(-0x7ffff  1)

.........

以此类推

逻辑上栈中的元素(a[i])始终是递减的

这样我们就通过以此循环求出了L数组 也就是找到了之前说的 最大区间的左边界 找右边界也是一样的思路,只是循环的方向不同

好了现在我们完成了第一步 要进行第二步 也就是找每个区间里面的最大连续和(如果a[i]<0的话需要找最小连续和)

如果a[i]均为非负的话就很简单了 肯定是区间越长 连续和越大 但问题是a[i]是可以有负数的

那就需要分情况讨论了

我们可以开4个数组 lmax lmin rmax rmin

lmax 和 rmax 用来记录最大连续和的区间的左右下标

lmin 和 rmin 记录最小的和的左右下标

怎么更新这四个数组呢?

for(i=2;i<=n;i++)    {        if(s[i-1]-s[lmin[i-1]-1]>0)        lmin[i]=i;        else        lmin[i]=lmin[i-1];        if(s[i-1]-s[lmax[i-1]-1]<0)        lmax[i]=i;        else        lmax[i]=lmax[i-1];    }

s[i]是前i项的和

看代码很容易理解 如果前面几项的和是正的 那就不要他 让lmin[i]=i 如果是负的 那么加上他 这样连续和就会变小

rmax和rmin只需要倒着更新就行

最后别忘了 这四个数组必须是在L数组和R数组的范围内的 相当于第一步是第二步的限制条件:

if(a[i]<0)        {            ll=max(l[i]+1,lmin[i]);            rr=min(r[i]-1,rmin[i]);        }        else        {            ll=max(l[i]+1,lmax[i]);            rr=min(r[i]-1,rmax[i]);        }

完整ac代码:

#include
using namespace std;long long i,n,ll,rr,s[500005],a[500005],lmin[500005],lmax[500005],rmin[500005],rmax[500005],l[500005],r[500005],ans;stack
S;int main(){ cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; s[i]=s[i-1]+a[i]; } ans=a[1]*a[1]; S.push(0); a[0]=-0x7fffff; a[n+1]=-0x7fffff-1; for(i=1;i<=n;i++) { while(a[S.top()]>=a[i]) S.pop(); l[i] = S.top(); S.push(i); } while(S.size()) S.pop(); S.push(n+1); for(i=n;i>=1;i--) { while(a[S.top()]>=a[i]) S.pop(); r[i]=S.top(); S.push(i); } lmin[1]=1; lmax[1]=1; rmin[n]=n; rmax[n]=n; for(i=2;i<=n;i++) { if(s[i-1]-s[lmin[i-1]-1]>0) lmin[i]=i; else lmin[i]=lmin[i-1]; if(s[i-1]-s[lmax[i-1]-1]<0) lmax[i]=i; else lmax[i]=lmax[i-1]; } for(i=n-1;i>=1;i--) { if(s[rmin[i+1]]-s[i]>0) rmin[i]=i; else rmin[i]=rmin[i+1]; if(s[rmax[i+1]]-s[i]<0) rmax[i]=i; else rmax[i]=rmax[i+1]; } for(i=1;i<=n;i++) { if(a[i]<0) { ll=max(l[i]+1,lmin[i]); rr=min(r[i]-1,rmin[i]); } else { ll=max(l[i]+1,lmax[i]); rr=min(r[i]-1,rmax[i]); } ans=max(ans,a[i]*(s[rr]-s[ll-1])); } cout<

 

转载于:https://www.cnblogs.com/dyhaohaoxuexi/p/10757005.html

你可能感兴趣的文章
约瑟夫环问题
查看>>
AI Conditional GAN
查看>>
结对编程_四则表达式生成
查看>>
SD卡状态变动receiver接收不到的问题
查看>>
Windows 7 SP1无人值守自动应答文件制作
查看>>
如何用WordPress做网站?
查看>>
Linux下gcc,g++,gdb,scon部分用法笔记
查看>>
Spring boot 1: 使用IDEA创建Spring boot项目
查看>>
经典SQL语句大全(转)
查看>>
多表查询
查看>>
assign和weak的深层次解析
查看>>
[string]字符串中几个比较难的算法和容易搞混的题目
查看>>
java integer String之equals vs ==
查看>>
调试maven源代码
查看>>
[转载]Java应用程序中的内存泄漏及内存管理
查看>>
算法体会以及常见机器学习算法公式
查看>>
css3属性之 box-sizing
查看>>
Essential reading: My top 10 books (zz)
查看>>
前端实现表格基于游览器固定显示
查看>>
Mac下安装 MongoDB
查看>>