zoukankan      html  css  js  c++  java
  • 2019牛客多校训练第四场C.sequence(线段树+单调栈+前缀和)

    题目传送门

    题意

    输入整数n,给出两个包含n个整数的序列a和b,找到一个区间[l,r],使在该区间内a序列最小值×b序列区间和的值最大。

    题解

    遍历a序列,维护单调栈求以当前值a[i]为最小值时的最大可达区间[ L[i],R[i] ](即最大左右边界);

    b序列先预处理其前缀和pre_sum,后用线段树维护pre_sum数组的区间最值;所以答案就是a[i]×b序列在[ L[i],R[i] ]区间内的和的最大值,不断更新最优解求最大结果即可。

    当a[i]≥0时,b序列在[ L[i],R[i] ]区间内的和的最大值为b序列前缀和数组后半部分最大值-前半部分最小值,即:

    max( [pre_sum(i),pre_sum(R[i])] )-min( [pre_sum(L[i]-1),pre_sum(i-1)] );

    当a[i]<0时,b序列在[ L[i],R[i] ]区间内的和的最大值为b序列前缀和数组后半部分最小值-前半部分最大值,即:

    min( [pre_sum(i),pre_sum(R[i])] )-max( [pre_sum(L[i]-1),pre_sum(i-1)] );

    时间复杂度O(nlogn)。

    Code

      1 /*2442ms*/
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 typedef long long ll;
      5 const int maxn=3e6+5;
      6 const ll inf=0x3f3f3f3f3f3f3f3fLL;
      7 ll a[maxn],b[maxn],pre_sum[maxn],L[maxn],R[maxn],sta[maxn];
      8 struct node
      9 {
     10     int l,r;//区间[l,r]
     11     ll mx;//区间最大值
     12     ll mn;//区间最小值
     13 }tree[maxn<<2];//一定要开到4倍多的空间
     14 void pushup(int index)
     15 {
     16     tree[index].mx=max(tree[index<<1].mx,tree[index<<1|1].mx);
     17     tree[index].mn=min(tree[index<<1].mn,tree[index<<1|1].mn);
     18 }
     19 void build(int l,int r,int index)
     20 {
     21     tree[index].l=l;
     22     tree[index].r=r;
     23     if(l==r){
     24         tree[index].mn=tree[index].mx=pre_sum[l];
     25         return;
     26     }
     27     int mid=(l+r)>>1;
     28     build(l,mid,index<<1);
     29     build(mid+1,r,index<<1|1);
     30     pushup(index);
     31 }
     32 ll queryMIN(int l,int r,int index)
     33 {
     34     if(l<=tree[index].l&&r>=tree[index].r)
     35         return tree[index].mn;
     36     int mid=(tree[index].l+tree[index].r)>>1;
     37     ll Min=inf;
     38     if(l<=mid)
     39         Min=min(queryMIN(l,r,index<<1),Min);
     40     if(r>mid)
     41         Min=min(queryMIN(l,r,index<<1|1),Min);
     42     return Min;
     43 }
     44 ll queryMAX(int l,int r,int index)
     45 {
     46     if(l<=tree[index].l&&r>=tree[index].r)
     47         return tree[index].mx;
     48     int mid=(tree[index].l+tree[index].r)>>1;
     49     ll Max=-inf;
     50     if(l<=mid)
     51         Max = max(queryMAX(l,r,index<<1),Max);
     52     if(r>mid)
     53         Max = max(queryMAX(l,r,index<<1|1),Max);
     54     return Max;
     55 }
     56 int main()
     57 {
     58     int n;
     59     while(~scanf("%d",&n))
     60     {
     61         for(int i=1;i<=n;i++)
     62             scanf("%lld",&a[i]);
     63         for(int i=1;i<=n;i++){
     64             scanf("%lld",&b[i]);
     65             pre_sum[i]=pre_sum[i-1]+b[i];//求b序列前缀和
     66         }
     67         build(0,n,1);
     68         /*单调栈求左端点L[i]*/
     69         int top=0;
     70         for(int i=1;i<=n;i++){
     71             while(top&&a[i]<=a[sta[top]])
     72                 top--;
     73             L[i]=(top==0)?1:sta[top]+1;
     74             sta[++top]=i;
     75         }
     76          /*单调栈求右端点R[i]*/
     77         top=0;
     78         for(int i=n;i>=1;i--){
     79             while(top&&a[i]<=a[sta[top]])
     80                 top--;
     81             R[i]=(top==0)?n:sta[top]-1;
     82             sta[++top]=i;
     83         }
     84         
     85         ll ans=-inf;
     86         for(int i=1;i<=n;i++){
     87             ll cnt=0;
     88             if(a[i]>0){
     89                 cnt=(queryMAX(i,R[i],1)-queryMIN(L[i]-1,i-1,1))*a[i];
     90             }
     91             else if(a[i]<0){
     92                 cnt=(queryMIN(i,R[i],1)-queryMAX(L[i]-1,i-1,1))*a[i];
     93             }
     94             else if(a[i]==0)
     95                 cnt=0;
     96             if(cnt>ans)ans=cnt;
     97         }
     98         printf("%lld
    ",ans);
     99     }
    100     return 0;
    101 }
    102 
    103 /*
    104 7
    105 -519 9794 1664 8189 -295 3471 1104
    106 -1796 -3137 7098 -3333 4683 -3968 467 3
    107 11811072
    108 */
    109 /*
    110 18
    111 -273 7169 -8145 -6664 -2970 698 8701 -6791 459 -5678 -846 8072 6384 5051 -3606 -4737 -9928 6815
    112 1609 -8810 9205 -9129 -1919 -116 -6752 385 4347 614 6261 4399 -8961 1022 -1360 -5074 7825 -122
    113 142708545
    114 */
    View Code
  • 相关阅读:
    bzoj 3572 [Hnoi2014]世界树 (虚树+树形dp)
    2018 计算之道初赛第二场 阿里巴巴的手机代理商(困难)(反向可持久化Trie)
    hdu 3089 (快速约瑟夫环)
    Codeforces Round #479 (Div. 3)
    牛客练习赛17
    BNU校赛总决赛J 小白兔小灰兔 相交计算几何模板
    2018BNU校赛总决赛
    Educational Codeforces Round 43 (Rated for Div. 2) ABCDE
    Codeforces Round #478 (Div. 2) ABCDE
    牛客练习赛 16
  • 原文地址:https://www.cnblogs.com/HOLLAY/p/11374517.html
Copyright © 2011-2022 走看看