牛客 小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; }
没有人不辛苦,只有人不喊疼