我们设f[i]=sigma(a[j])(1<=j<=i)
那么对于每一关,它的答案即是前面的点(sigma(a[j-1]),j*d)与 (sigma(a[i]),x[i]+i*d)的斜率的最大值
经过观察我们发现最优解一定在下凸壳上,而且凸壳上的斜率是一个单峰函数,因些我们可以维护(sigma[i-1],i*d)的下凸壳,每次在凸壳上三分求解
哦。最后那个保留到整数是四舍五入哈。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
struct point{
double x,y;
point(double _x=0,double _y=0){
x=_x;y=_y;
}
};
point operator +(point a,point b){return point(a.x+b.x,a.y+b.y);}
point operator -(point a,point b){return point(a.x-b.x,a.y-b.y);}
double operator ^(point a,point b){return a.x*b.y-a.y*b.x;}
double xl(point a,point b)
{
return (b.y-a.y)/(b.x-a.x);
}
point tu[100011],ne;
double tmp,a[100011],x[100011],pre[100011],d;
double ans;
int i,n,t;
double find(point x)
{
int fn,i,l,r,mid1,mid2;
double ans1,ans2,ret;
l=1;
r=t;
while(l+2<r){
fn=(r-l)/3;
mid1=l+fn;mid2=mid1+fn;
ans1=xl(tu[mid1],x);ans2=xl(tu[mid2],x);
if(ans1<ans2)l=mid1+1;
else r=mid2-1;
}
ret=0;
for(i=l;i<=r;i++)ret=max(ret,xl(tu[i],x));
return ret;
}
int main()
{
scanf("%d%lf",&n,&d);
for(i=1;i<=n;i++){
scanf("%lf%lf",&a[i],&x[i]);
pre[i]=pre[i-1]+a[i];
}
for(i=1;i<=n;i++){
ne=point(i*d,pre[i-1]);
while(t>1&&((tu[t]-tu[t-1])^(ne-tu[t-1]))<0)t--;
tu[++t]=ne;
ne=point(x[i]+i*d,pre[i]);
ans+=find(ne);
}
printf("%.0lf
",ans);
}