[Sdoi2013]保护出题人

题目链接: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值