好像不是很难,就是普通的CDQ分治,每次统计左边对右边的贡献
/* @Date : 2019-08-15 20:38:48 @Author : Adscn (adscn@qq.com) @Link : https://www.cnblogs.com/LLCSBlog */ #include<bits/stdc++.h> using namespace std; #define int long long #define IL inline #define RG register #define gi getint() #define gc getchar() #define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout) IL int getint() { RG int xi=0; RG char ch=gc; bool f=0; while(ch<'0'||ch>'9')ch=='-'?f=1:f,ch=gc; while(ch>='0'&&ch<='9')xi=(xi<<1)+(xi<<3)+ch-48,ch=gc; return f?-xi:xi; } template<typename T> IL void pi(T k,char ch=0) { if(k<0)k=-k,putchar('-'); if(k>=10)pi(k/10,0); putchar(k%10+'0'); if(ch)putchar(ch); } const int N=5e5+7; int n,S; int c[N],t[N]; typedef long long ll; ll f[N]; struct oper { ll x,y,k; int id; bool operator <(const oper & b)const{ return k<b.k; } }qry[N],tmp[N]; inline ll Y(int j,int k){return qry[k].y-qry[j].y;} inline ll X(int j,int k){return qry[k].x-qry[j].x;} inline bool cmp(const oper &a,const oper &b){ return a.x==b.x?a.y<b.y:a.x<b.x; } inline void cdq(int L,int R) { if(L==R){ qry[L].x=c[L]; qry[L].y=f[L]-c[n]*t[L]+c[L]*t[L]-S*c[L]; return; } int mid=(L+R)>>1; int l=L,r=mid+1; for(int i=L;i<=R;++i) if(qry[i].id>mid)tmp[r++]=qry[i]; else tmp[l++]=qry[i]; memcpy(qry+L,tmp+L,sizeof(oper)*(R-L+1)); cdq(L,mid); static int stk[N]; int top=0; for(int i=L;i<=mid;++i) { while(top>1&&(ll)Y(stk[top-1],stk[top])*X(stk[top-1],i)>(ll)Y(stk[top-1],i)*X(stk[top-1],stk[top]))--top; stk[++top]=i; } int h=1; for(int i=mid+1;i<=R;++i) { while(h<top&&(ll)Y(stk[h],stk[h+1])<(ll)qry[i].k*X(stk[h],stk[h+1]))++h; int I=qry[i].id,j=stk[h]; f[I]=min(f[I],-qry[i].k*qry[j].x+qry[j].y+c[n]*(t[I]+S)); } cdq(mid+1,R); l=L,r=mid+1; for(int i=L;i<=R;++i) if((r>R||cmp(qry[l],qry[r]))&&l<=mid)tmp[i]=qry[l++]; else tmp[i]=qry[r++]; memcpy(qry+L,tmp+L,sizeof(oper)*(R-L+1)); } signed main(void) { n=gi,S=gi; for(int i=1;i<=n;++i)t[i]=gi+t[i-1],c[i]=gi+c[i-1]; for(int i=1;i<=n;++i)qry[i].id=i,qry[i].k=t[i],f[i]=1e18; sort(qry+1,qry+n+1); cdq(0,n); return pi(f[n]),0; }