题目链接:https://nanti.jisuanke.com/t/38228

题意:在给出的序列里面找一个区间,使区间最小值乘以区间和得到的值最大,输出这个最大值。

思路:我们枚举每一个数字,假设是a[i],那么我们就要找一个包含a[i]的区间,并且这个区间里面的最小值就是a[i],使a[i]乘以这个区间的区间和最大,一直更新这个最大值就可以了。

要保证区间最小值为a[i],那么就要找下标i左边第一个小于a[i]的数字所在下标和右边第一个小于a[i]的数字下标,我们在这两个下标围成的区间里面找最优的区间和,这个用单调栈,线段树什么的都可以做到,这里用单调栈,因为最快,是线性的。求出每一个数字左右两边第一个比他小的数字下标。L[i]表示左边第一个比a[i]小的数字下标,R[i]表示右边第一个比a[i]小的数字下标,s是一个栈,里面存的是下标。

代码:

  1. //单调栈找每个数字左右两边比自己小的数字位置
  2. for(int i=;i<=n;i++){
  3. while(!s.empty()&&a[s.top()]>a[i]){//在保证栈不为空的情况下把栈顶大于a[i]的
  4. //元素弹出,并把R[s.top()]赋值为i
  5. R[s.top()]=i;
  6. s.pop();
  7. }
  8. if(!s.empty()){//如果栈不为空,那么栈顶有比a[i]小的数字
  9. if(a[s.top()]!=a[i])//如果这个栈顶数字不是a[i],L[i]=s.top()
  10. L[i]=s.top();
  11. else //如果栈顶数字也是自己,那么向右递推,L[i]=L[s.top()]
  12. L[i]=L[s.top()];
  13. }
  14. else
  15. L[i]=;//栈为空,没有小于a[i]的数字
  16. s.push(i);//把当前数字压入栈
  17. }
  18. while(!s.empty()){
  19. R[s.top()]=n+;
  20. s.pop();
  21. }

我们用前缀和建线段树,一个叶子节点代表一个前缀和。

如果a[i]是一个正数,那么这个区间就要是a[i]为区间最小值,并且区间和尽量大。我们在区间[L[i],i-1]里找一个最小的前缀和,在区间[i,R[i]-1]里找一个最大的前缀和,用最大的减最小的就得到了包含a[i]的最大区间和。

如果a[i]是一个负数,那么这个区间就要是a[i]为区间最小值,并且区间和尽量小。我们在区间[L[i],i-1]里找一个最大的前缀和,在区间[i,R[i]-1]里找一个最小的前缀和,用最小的减最大的就是包含a[i]的最小区间和。

然后一直更新就可以了,最后注意n最大是5乘10的5次方...

代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<map>
  6. #include<stack>
  7. #include<cmath>
  8. #include<vector>
  9. #include<set>
  10. #include<cstdio>
  11. #include<string>
  12. #include<deque>
  13. using namespace std;
  14. typedef long long LL;
  15. #define eps 1e-8
  16. #define INF 0xfffffffffffff
  17. #define maxn 500005
  18. int a[maxn],L[maxn],R[maxn];
  19. LL sum[maxn];
  20. int n,m,k,t;
  21. stack<int>s;
  22. struct node{
  23. LL Max,Min;
  24. }tree[maxn<<];
  25. void update(int k){
  26. tree[k].Max=max(tree[k<<].Max,tree[k<<|].Max);
  27. tree[k].Min=min(tree[k<<].Min,tree[k<<|].Min);
  28. }
  29. void build(int l,int r,int k){//建树
  30. if(l==r){
  31. tree[k].Max=tree[k].Min=sum[l];
  32. return;
  33. }
  34. int mid=(l+r)/;
  35. build(l,mid,k<<);
  36. build(mid+,r,k<<|);
  37. update(k);
  38. }
  39. LL ask_Max(int l,int r,int k,int L,int R){
  40. if(l>=L&&r<=R){
  41. return tree[k].Max;
  42. }
  43. int mid=(l+r)/;
  44. LL ans=-INF;
  45. if(L<=mid)
  46. ans=max(ans,ask_Max(l,mid,k<<,L,R));
  47. if(R>mid)
  48. ans=max(ans,ask_Max(mid+,r,k<<|,L,R));
  49. return ans;
  50.  
  51. }
  52. LL ask_Min(int l,int r,int k,int L,int R){
  53. if(l>=L&&r<=R){
  54. return tree[k].Min;
  55. }
  56. int mid=(l+r)/;
  57. LL ans=INF;
  58. if(L<=mid)
  59. ans=min(ans,ask_Min(l,mid,k<<,L,R));
  60. if(R>mid)
  61. ans=min(ans,ask_Min(mid+,r,k<<|,L,R));
  62. return ans;
  63.  
  64. }
  65. int main()
  66. {
  67. while(scanf("%d",&n)!=EOF){
  68. while(!s.empty())
  69. s.pop();
  70. sum[]=;
  71. for(int i=;i<=n;i++){
  72. scanf("%d",&a[i]);
  73. sum[i]=sum[i-]+a[i];
  74. }
  75. //单调栈找每个数字左右两边比自己小的数字位置
  76. for(int i=;i<=n;i++){
  77. while(!s.empty()&&a[s.top()]>a[i]){//在保证栈不为空的情况下把栈顶大于a[i]的
  78. //元素弹出,并把R[s.top()]赋值为i
  79. R[s.top()]=i;
  80. s.pop();
  81. }
  82. if(!s.empty()){//如果栈不为空,那么栈顶有比a[i]小的数字
  83. if(a[s.top()]!=a[i])//如果这个栈顶数字不是a[i],L[i]=s.top()
  84. L[i]=s.top();
  85. else //如果栈顶数字也是自己,那么递推,L[i]=L[s.top()]
  86. L[i]=L[s.top()];
  87. }
  88. else
  89. L[i]=;//栈为空,没有小于a[i]的数字
  90. s.push(i);//把当前数字压入栈
  91. }
  92. while(!s.empty()){
  93. R[s.top()]=n+;
  94. s.pop();
  95. }
  96.  
  97. build(,n,);
  98. LL ans=-INF;
  99. for(int i=;i<=n;i++){
  100. if(a[i]>=){//a[i]大于等于0,求左边最小的前缀和,右边最大的前缀和,右边减左边,得到包含a[i]的最大区间和
  101. LL Min=ask_Min(,n,,L[i],i-);
  102. LL Max=ask_Max(,n,,i,R[i]-);
  103. ans=max(ans,a[i]*(Max-Min));
  104. }else{//a[i]小于0,求左边最大的前缀和,右边最小的前缀和,右边减左边,得到包含a[i]的最小区间和
  105. LL Min=ask_Min(,n,,i,R[i]-);
  106. LL Max=ask_Max(,n,,L[i],i-);
  107. ans=max(ans,a[i]*(Min-Max));
  108. }
  109. }
  110. printf("%lld\n",ans);
  111. }
  112. return ;
  113. }

网络赛 I题 Max answer 单调栈+线段树的更多相关文章

  1. 2019ICPC南昌邀请赛网络赛 I. Max answer (单调栈+线段树/笛卡尔树)

    题目链接 题意:求一个序列的最大的(区间最小值*区间和) 线段树做法:用单调栈求出每个数两边比它大的左右边界,然后用线段树求出每段区间的和sum.最小前缀lsum.最小后缀rsum,枚举每个数a[i] ...

  2. 南昌邀请赛I.Max answer 单调栈+线段树

    题目链接:https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value of a in ...

  3. The Preliminary Contest for ICPC China Nanchang National Invitational I. Max answer (单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题目大意:一个区间的值等于该区间的和乘以区间的最小值.给出一个含有n个数的序列(序列的值有正有负),找到该序列的区间最大 ...

  4. 洛谷P4198 楼房重建 单调栈+线段树

    正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...

  5. 2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树)

    2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树) 传送门:https://nanti.jisuanke.com/t/41296 题意: 给一个数列A 问在数列A中有多 ...

  6. 南昌网络赛 I. Max answer (单调栈 + 线段树)

    https://nanti.jisuanke.com/t/38228 题意给你一个序列,对于每个连续子区间,有一个价值,等与这个区间和×区间最小值,求所有子区间的最大价值是多少. 分析:我们先用单调栈 ...

  7. The Preliminary Contest for ICPC China Nanchang National Invitational I.Max answer单调栈

    题面 题意:一个5e5的数组,定义一个区间的值为 这个区间的和*这个区间的最小值,注意数组值有负数有正数,求所有区间中最大的值 题解:如果全是正数,那就是原题 POJ2796 单调栈做一下就ok 我们 ...

  8. 2019南昌网络赛-I(单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上 ...

  9. Codeforces - 1199D - Welfare State - 单调栈 / 线段树

    https://codeforc.es/contest/1199/problem/D 其实后来想了一下貌似是个线段树的傻逼题. 单调栈是这样思考的,每次单点修改打上一个最终修改的时间戳.每次全体修改就 ...

随机推荐

  1. http协议和telnet指令讲解

    http协议: 1.http:是网络传输协议:全称为:超文本传输协议: 关系:客户端和服务器的关系: 协议:就是一种规范: 常见的http和https两种,https是http的升级版 http协议: ...

  2. linux中.nfsxxxx引起的文件无法删除

    一个linux系统中的某个文件夹无法删除,使用ls -al查看有1个.nfsxxxx的文件无法删除. 使用lsof +D /filepath/,查看到文件被一个进程一直占用. 再使用ps -aux | ...

  3. 记录1-更换mac pro内存,硬盘及恢复系统

    我的mac pro是2012年初买的,4G/500G HDD在服役了六年多后速度堪比老牛,以前装的虚拟机压根不敢打开.这几天把内存更换为8G,硬盘升级为samsung的1T SSD,感觉像起死回生一样 ...

  4. (整理)REHL6.5_Yum安装Reids

    1.yum添加epel源 yum install epel-release 默认安装,遇到“确定吗?”输入Y 2.yum安装Redis yum install redis  默认安装,遇到“确定吗?” ...

  5. 最近想学Json,请问大家有没有什么好的Json教程介绍一下?

    最近想学json,请问大家有没有什么好的Json教程介绍一下? 最近学完java的框架了,想了解一下json,可是找不到相关视频,请大家有这方面的Json教程好资料就介绍下啦,最后有网址链接啦. {} ...

  6. udt的java实现

    udt协议是什么? 我就不回答了,可以网上搜索,一直都是c++的,java的实现已经很久没有修改了 经过测试,java版本有些一问题,现在已经将其修复,已经上传到csdn 另外自己根据实际的应用,再次 ...

  7. Appium java环境搭建(Windows版)

    注意:如果初次学习appium的话,则需要你做好准备因为安装过程并不简单 1.安装appium Appium 官方网站:http://appium.io/ 安装Appium之前需要先安装node.js ...

  8. cgi fast-cig php-fpm

    cgi 通用网关接口,接受到动态请求,web服务器会根据这次请求的内容,然后会fork一个新进程来运行, 这个进程会把处理完的数据返回给web服务器,最后web服务器把内容发送给用户,刚才fork的进 ...

  9. Spring获取URL相关信息

    获取请求的URL:request.getRequestURL().toString(); 获取上下文名称(项目名称):request.getContextPath()

  10. JAVA 8 函数式接口--Consumer

    从JDK8开始java支持函数式编程,JDK也提供了几个常用的函数式接口,这篇主要介绍Consumer接口.文本介绍的顺序依次为: 源码介绍 使用实例 jdk内对Consumer的典型使用 扩展类介绍 ...