题意:
在一个诡异的植物大战僵尸游戏中,给出n关;
第i关队首僵尸距房门xi,两个僵尸之间间隔为d;
每次在队首添加一个血量为ai的僵尸,其他僵尸不变;
每关在门前放一个攻击力任意的植物,求n关放置植物总攻击力的最小值;
n<=100000,其他数据<=10^12;
题解:
题意叙述略诡异。。建议还是去看一眼原题;
首先考虑对于每一关的答案,应该是恰好将最难打死的僵尸打死的攻击力值;
令s[i]为i这个僵尸血量与它前面僵尸血量之和,dis[i]为这个僵尸距房门的距离;
那么答案就是ans=max(s[i]/dis[i]);
将这个东西视为一个二维坐标系下的点,要求的就是这个点集与原点斜率最大的地方;
这里我是维护一个上凸壳来二分(为啥别人都是下凸壳);
二分详细还是见代码吧。。我最近各种姿势都有些奇怪;
上凸壳的原因似乎比较显然吧,上凸出来的一个东西可以是答案而下凹进去的绝对不可能啊;
这样对于一个答案的处理就可以做到logn了吧;
但是两关之间的转移,如果一个一个移动点是O(n)的,就又退化到了暴力;
所以不能移动点,移动坐标轴!
然后这题似乎就没啥说的了,最后一句吐槽,我并不想保护出题人;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
using namespace std;
typedef long long ll;
int st[N],top;
ll x[N],y[N];
double slope(int l,int r)
{
if(!r) return -1e100;
if(x[l]==x[r])
return y[l]<y[r]?1e100:-1e100;
return (double(y[l]-y[r]))/(x[l]-x[r]);
}
int main()
{
int n,i,j,k,l,r,mid;
ll d,a,xi,lastx;
double ans=0;
scanf("%d%lld",&n,&d);
lastx=d;
for(i=1;i<=n;i++)
{
scanf("%lld%lld",&a,&xi);
x[0]-=d+xi-lastx;
y[0]-=a;
lastx=xi;
x[i]=x[0]+xi;
y[i]=y[0]+a;
while(top>1&&slope(st[top],st[top-1])>=slope(i,st[top]))
st[top--]=0;
st[++top]=i;
l=1,r=top;
while(l<=r)
{
mid=l+r>>1;
if(slope(0,st[mid])>slope(0,st[mid-1]))
l=mid+1;
else
r=mid-1;
}
ans+=slope(0,st[r]);
}
printf("%.0lf",ans);
return 0;
}