牛客 小A与最大子段和(斜率优化dp)

这道题也是斜率优化的题目,可以用代数法化简,但是本题有个问题是

直线的斜率不一定递增,所以需要二分查找。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e5+20;
typedef long long ll;
ll a[N],f[N],q[N],s[N],b[N];
ll getup(int i,int j){
    return i*b[i]-s[i]-(j*b[j]-s[j]);
}
int getdown(int i,int j){
    return i-j;
}
int bs(int l,int r,ll val){
    while(l<r){
        int mid=(l+r)/2;
        if(getup(q[mid+1],q[mid])>val*(q[mid+1]-q[mid]))
            l=mid+1;
        else
            r=mid;
    }
    return l;
}
int main(){
    int i;
    int n;
    cin>>n;
    for(i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        b[i]=b[i-1]+a[i];
        a[i]*=i;
        s[i]=s[i-1]+a[i];
    }
    ll res=-1e18;
    int tt=0;
    int hh=0;
    for(i=1;i<=n;i++){
        int l=hh,r=tt;
        int ans=bs(l,r,b[i]);
        f[i]=s[i]-s[q[ans]]-q[ans]*(b[i]-b[q[ans]]);
        res=max(res,f[i]);
        while(hh<tt&&getup(q[tt],q[tt-1])*getdown(i,q[tt])<=getup(i,q[tt])*getdown(q[tt],q[tt-1]))
            tt--;
        q[++tt]=i;
    }
    cout<<res<<endl;
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12552358.html