欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

BZOJ3203 保护出题人(defend)

程序员文章站 2022-04-01 16:12:05
...

保护出题人(defend)

题目描述

 

BZOJ3203 保护出题人(defend)

 

输入

 

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

 

输出

 

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

 

样例输入

5 2
3 3
1 1
10 8
4 8
2 3

样例输出

7

提示

 

BZOJ3203 保护出题人(defend)

 

来源

sdoi2013R2day2


solution

把ai前缀和起来

得到一个式子:BZOJ3203 保护出题人(defend)

拆开 BZOJ3203 保护出题人(defend)

很像BZOJ3203 保护出题人(defend)

显然凸包上的点有用,那就把( aj,-j*d ) 建凸包。

对于点(a[i],i*d+x[i]) 斜率是单峰的。

那么可以三分。

注意整数三分

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 1000005
#define ll long long
using namespace std;
ll n,d,top;
double ans;
struct node{
    ll a,x;
}s[maxn];
struct po{
    ll x,y;
}zh[maxn],nex,q;
po xl(po a,po b){
    po t;
    t.x=a.x-b.x;t.y=a.y-b.y;
    return t;
}
ll cj(po a,po b){
    return a.x*b.y-a.y*b.x;
}
double getk(po a,po b){
    double dx=a.x-b.x,dy=a.y-b.y;
    return dy/dx;
}
double ask(po q){
    ll l=1,r=top;
    while(r-l>=3){//zhengshu sanfen
        int lm=l+(r-l)/3,rm=r-(r-l)/3;
        double k1=getk(zh[lm],q),k2=getk(zh[rm],q);
        if(k1>k2)r=rm;
        else l=lm;
    }
    double fs=0;
    for(ll i=l;i<=r;i++)
        fs=max(fs,getk(zh[i],q));
    return fs;
}
int main()
{
    cin>>n>>d;
    for(ll i=1;i<=n;i++){
        scanf("%lld%lld",&s[i].a,&s[i].x);
        s[i].a+=s[i-1].a;
    }
    for(ll i=1;i<=n;i++){
        nex.x=d*i;nex.y=s[i-1].a;
        while(top>1&&cj(xl(zh[top],zh[top-1]),xl(nex,zh[top]))<0)top--;
        zh[++top]=nex;
        q.x=s[i].x+d*i;q.y=s[i].a;
        ans+=ask(q);
    }
    printf("%.0lf\n",ans);
    return 0;
}

 

相关标签: 凸包