斜率优化——bzoj1010
把hdu3507的式子转化一下就行
#include<bits/stdc++.h> using namespace std; #define ll long long #define N 500005 struct point{ ll x,y;//x=sum[i],y=dp[i]+sum[i]*sum[i] point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};} point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};} }; ll cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} ll n,L,dp[N],a[N],sum[N],t[N]; point q[N]; int head,tail; void pop(ll k){//sum[i]显然递增,所以可以把前面斜率<=k的全部pop掉 while(tail>head && q[head+1].y-q[head].y<=k*(q[head+1].x-q[head].x)) head++; } void push(point k1){//sum[i]递增,所以必定可以更新凸包 while(tail>head && cross(q[tail]-k1,q[tail-1]-k1)>=0)tail--; q[++tail]=k1; } int main(){ while(cin>>n>>L){ memset(sum,0,sizeof sum); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++)t[i]=sum[i]+i; dp[0]=0;tail=head=1; q[tail]=((point){0,0}); for(int i=1;i<=n;i++){ pop(2*t[i]);//在凸包上找到该斜率对应的点 dp[i]=t[i]*t[i]+(L+1)*(L+1)-2*t[i]*(L+1); dp[i]+=-2*t[i]*q[head].x+q[head].y; push((point){t[i],dp[i]+t[i]*t[i]+2*t[i]*(L+1)});//把第i个点更新到二维坐标轴上,更新凸包 //cout<<i<<" "<<dp[i]<<" "<<q[head].x<<" "<<q[head].y<<" "<<head<<" "<<tail<<endl; } cout<<dp[n]<<'\n'; } }