您的位置:首页 > 其它

bzoj-3203 保护出题人

2015-08-09 10:23 218 查看
题意:

在一个诡异的植物大战僵尸游戏中,给出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
,top;
ll x
,y
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: