标签:
我们设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\n",ans); }
标签:
原文地址:http://www.cnblogs.com/applejxt/p/4480839.html