[bzoj3203][三分]保护出题人

Description

[bzoj3203][三分]保护出题人_第1张图片

Input

第一行两个空格隔开的正整数n和d,分别表示关数和相邻僵尸间的距离。接下来n行每行两个空格隔开的正整数,第i + 1行为Ai和
Xi,分别表示相比上一关在僵尸队列排头增加血量为Ai 点的僵尸,排头僵尸从距离房子Xi米处开始接近。

Output

一个数,n关植物攻击力的最小总和 ,保留到整数。

Sample Input

5 2

3 3

1 1

10 8

4 8

2 3

Sample Output

7

HINT

第一关:距离房子3米处有一只血量3点的僵尸,植物最小攻击力为1.00000;
第二关:距离房子1米处有一只血量1点的僵尸、3米处有血量3点的僵尸,植物最小攻击力为1.33333;
第三关:距离房子8米处有一只血量10点的僵尸、10米处有血量1点的僵尸、12米处有血量3点的僵尸,植物最小攻击力为1.25000;
第四关:距离房子8米处有一只血量4点的僵尸、10米处有血量10点的僵尸、12米处有血量1点的僵尸、14米处有血量3点的僵尸,植物最小攻击力为1.40000;
第五关:距离房子3米处有一只血量2点的僵尸、5米处有血量4点的僵尸、7米处有
血量10点的僵尸、9米处有血量1点的僵尸、11米处有血量3点的僵尸,植物最小攻击力 为2.28571。
植物攻击力的最小总和为7.26905。

对于100%的数据, 1≤n≤10^5,1≤d≤10^12,1≤x≤ 10^12,1≤a≤10^12

题解

这题很强
一开始以为是道水题2333…然后就挂了
可以搞出来一个式子
ans=max((s[i]s[j1])/(Xi+d(ij))) a n s = m a x ( ( s [ i ] − s [ j − 1 ] ) / ( X i + d ∗ ( i − j ) ) )
其中s表示A的前缀和
意思就是打死每个僵尸所需要的攻击力嘛
我们设两个点 Q(x1,y1),P(x2,y2) Q ( x 1 , y 1 ) , P ( x 2 , y 2 )
其中 y1=s[i],x1=Xi+di y 1 = s [ i ] , x 1 = X i + d ∗ i
y2=s[j1],x2=dj y 2 = s [ j − 1 ] , x 2 = d ∗ j
然后就可以化简成
ans=max((y2y1)/(x2x1)) a n s = m a x ( ( y 2 − y 1 ) / ( x 2 − x 1 ) )
这是一个斜率的形式,那么问题转化为给一个点和其他一些点,求这个点到其他一些点的最大斜率
N^2的做法肯定是不兹磁的
画画图可以发现,这些点一定在一个下凸包上
于是每次输入可以用单调栈维护下凸包
发现答案满足三分性,三分答案即可
输入不能输longlong然后强制转double????

#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
struct pt{double x,y;}sta[110000];
int n,D,top;
double slop(pt u,pt v){return (v.y-u.y)/(v.x-u.x);}
double s[110000];
double ans;
int main()
{
    scanf("%d%d",&n,&D);
    top=0;
    for(int T=1;T<=n;T++)
    {
        double A,X;
        scanf("%lf%lf",&A,&X);
        s[T]=s[T-1]+A;
        pt tmp;tmp.x=D*double(T);tmp.y=s[T-1];
        while(top && slop(sta[top-1],sta[top])>=slop(sta[top],tmp))top--;
        sta[++top]=tmp;
        tmp.x=X+D*double(T);tmp.y=s[T];
        int l=1,r=top;
        while(r-l>3)
        {
            int mid=(l+r)/2;
            int mmid=(mid+r)/2;
            if(slop(tmp,sta[mid])>slop(tmp,sta[mmid]))r=mmid-1;
            else l=mid+1;
        }
        int op=l;
        for(int i=l+1;i<=r;i++)
            if(slop(tmp,sta[i])>slop(tmp,sta[op]))op=i;
        ans+=slop(tmp,sta[op]);
    }
    printf("%.0lf\n",ans);
    return 0;
}

你可能感兴趣的:(bzoj,三分)