• [小A与最大子段和][斜率优化dp+二分]


    链接:https://ac.nowcoder.com/acm/contest/545/A
    来源:牛客网
    题目描述

    小A在网上看到了 "最大子段和" 问题的解法.第二天,小A向小B讲解了这个问题.
    但小B抛出了一个疑问:如果让每个数的权值是它本身的值乘上它在子段中的位置呢?
    小A被难住了,你能帮他解决这个问题吗?
    形式化地说,你需要在一个序列 a  里找到一个非空子段(子段是连续的) b, 满足 mi=1b[i]×i∑i=1mb[i]×i 最大( m 是 b 的长度)
    输入描述:
    第一行一个整数 n ,表示序列的长度
    第二行 n 个整数,第 i 个数表示 aiai
    输出描述:
    一行一个整数,表示最大的 mi=1b[i]×i∑i=1mb[i]×i 
    示例1
    输入
    4
    -100 1 2 3
    输出

    14

    说明
    1×1+2×2+3×3=141×1+2×2+3×3=14

    备注:
    1n2×10^5
    0ai|2×10^3

    题解:枚举每个区间右端点,如果再枚举左端点则复杂度为O(N^2)不可行。使用斜率优化。

    令s为前缀和,p[i] = ∑(i * s[i]),区间[j, i]以i为右端点时区间和可以表示为p[i] - p[j - 1] - (j - 1) * (s[i] - s[j - 1])。

    斜率方程(k < j < i) j比k优,((j * s[j] - p[j]) - (k * s[k] - p[k])) / (j - k) > s[i],由于前缀和s不单调所以不能直接将队首节点弹出,(即只通过插入当前点更新队尾元素,不能丢弃队首元素,【而如果前缀和s单调,易知队首元素在当前不满足时也不会满足以后的点即可以丢弃】)
    所以就不能通过丢弃队首来找满足条件的点了,只能通过二分斜率凸包来找满足条件的斜率。
     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstdio>
     6 #include<queue>
     7 #include<time.h>
     8 using namespace std;
     9 typedef long long ll;
    10 const int N = 2e5+10;
    11 ll a[N],A[N],B[N],dp[N];
    12 struct pot{
    13     int x;
    14     ll y;
    15 }que[N];
    16 int head=1;
    17 int tail=0;
    18 bool check(int s,int k){
    19     if(tail<2)return true;
    20     return que[s].y-que[s-1].y<(que[s].x-que[s-1].x)*B[k];
    21 }
    22 int main(){
    23     int n;
    24     scanf("%d",&n);
    25     for(int i=1;i<=n;i++){scanf("%lld",&a[i]);dp[i]=a[i];}
    26     for(int i=1;i<=n;i++){
    27         A[i]=i*a[i]+A[i-1];
    28         B[i]=a[i]+B[i-1];
    29     }
    30     ll ans=-10000000;
    31     for(int i=1;i<=n;i++){
    32         int l=head;
    33         int r=tail;
    34         int m=l;
    35         while(l<=r){
    36             int mid=(l+r)/2;
    37             if(check(mid,i)){
    38                 m=mid;
    39                 r=mid-1;
    40             }
    41             else l=mid+1;
    42         }
    43         dp[i]=max(A[i]-A[que[m-1].x]-que[m-1].x*(B[i]-B[que[m-1].x]),dp[i]);
    44         ans=max(ans,dp[i]);
    45         while(tail>=2&&(i*B[i]-A[i]-(que[tail].y))*(que[tail].x-que[tail-1].x)>(i-que[tail].x)*((que[tail].y-que[tail-1].y)))tail--;
    46         que[++tail].x=i;
    47         que[tail].y=i*B[i]-A[i];
    48     }
    49     cout<<ans<<endl;
    50     return 0;
    51 }
    View Code
     
     

     

  • 相关阅读:
    java 代码规范 sun 公司
    软引用、弱引用、虚引用
    socket
    httpURLConnection、URL、httpClient、httpPost、httpGet
    android service aidl 理解
    Python2.7-codecs
    Python2.7-textwrap
    Python2.7-StringIO和cStringIO
    Python2.7-difflib
    Python2.7-struct模块
  • 原文地址:https://www.cnblogs.com/MekakuCityActor/p/10626296.html
Copyright © 2020-2023  润新知