题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3203
解法:
本题读完题目,我们可以很快知道,对于第i轮,yi的最小值就是max(sum[i]-sum[j-1])/(xi+(i-j)*d),1<=j<=i。其中sum[i]=sigma(a[j]),1<=j<=i。
这样我们可以得到一个n^2的算法。
观察式子,我们可以发现,它的集合意义就是P(sum[i],x[i]+i*d)到所有Q(sum[j-1],j*d)连线的最大值。
显然Q,P都是定点。接下来我们看怎么才能取到斜率最大呢?。很显然的一个结论是取到max的点在Q的凸壳上。
如图,kPQ'<kPQ,我们总是可以把凸壳内的点拉到凸壳上获得更大的斜率= =。
接着就是在凸壳上求最大斜率,又有个很显然的结论就是凸壳上到P的斜率是个单峰函数。如下图:
kPQ1<kPQ2<kPQ3,kPQ3>kPQ4>kPQ5。。是不是很显然
然后我们三分就好了。就可以算出最大斜率了。
代码:(这是BZOJ上目前rank1的)
/**************************************************************
Problem: 3203
User: hta
Language: C++
Result: Accepted
Time:216 ms
Memory:4396 kb
****************************************************************/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
const int maxn=100003,lim=0;
const double eps=1e-18;
typedef long long LL;
int n;
double d,a[maxn],x[maxn],ans=0;
struct Tpoint
{
double x,y;
Tpoint(){}
Tpoint(double _x,double _y){x=_x,y=_y;}
Tpoint operator -(const Tpoint &b)const{return Tpoint(x-b.x,y-b.y);}
double operator *(const Tpoint &b)const{return x*b.y-y*b.x;}
}s[maxn];
inline LL get()
{
LL f=0,v=0;char ch;
while(!isdigit(ch=getchar()))if(ch=='-')break;
if(ch=='-')f=1;else v=ch-48;
while(isdigit(ch=getchar()))v=v*10+ch-48;
if(f==1)return -v;else return v;
}
inline int sig(double x){return fabs(x)<=eps?0:(x>eps?1:-1);}
inline double slope(const Tpoint &a,const Tpoint &b){return (a.y-b.y)/(a.x-b.x);}
int main()
{
n=get(),d=get();
for(int i=1;i<=n;i++)a[i]=get(),x[i]=get();
double sum=0;
int top=0;
for(int i=1;i<=n;i++)
{
Tpoint p=Tpoint(i*d,sum);sum+=a[i];
while(top>1&&sig((p-s[top-1])*(s[top]-s[top-1]))>=0)top--;
s[++top]=p;
p=Tpoint(x[i]+i*d,sum);
int l=1,r=top,m1,m2;
while(r-l>=3)
{
m1=l+(r-l)/3,m2=r-(r-l)/3;
double k1=slope(s[m1],p),k2=slope(s[m2],p);
if(k1<k2)l=m1;else r=m2;
}
double res=0;
for(int j=l;j<=r;j++)res=max(res,slope(s[j],p));
ans+=res;
}
printf("%.0lf\n",ans);
return 0;
}