在一个诡异的植物大战僵尸游戏中,给出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; }
原文地址:http://blog.csdn.net/ww140142/article/details/47373653