Description
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
Source
感人至深…最后我竟然没发现答案是在凸包上所以可以三分T_T
hta的题解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100010
#define eps 1e-20
using namespace std;
int n,top;
double d,ans;
double a[MAXN],x[MAXN];
struct Point
{
double x,y;
friend Point operator +(Point a,Point b) {return (Point){a.x+b.x,a.y+b.y};}
friend Point operator -(Point a,Point b) {return (Point){a.x-b.x,a.y-b.y};}
friend double operator *(Point a,Point b) {return a.x*b.y-a.y*b.x;}
}sta[MAXN];
double slope(Point a,Point b) {return (a.y-b.y)/(a.x-b.x);}
int main()
{
scanf("%d%lf",&n,&d);double sum=0,maxn=0;
for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i],&x[i]);
for (int i=1;i<=n;i++)
{
maxn=0;Point now=(Point){i*d,sum};sum+=a[i];
while (top>1&&(now-sta[top-1])*(sta[top]-sta[top-1])>=-eps) top--;
sta[++top]=now;now=(Point){x[i]+i*d,sum};
int l=1,r=top,mid1,mid2,len;
while (r-l>=3)
{
len=(r-l+1)/3;mid1=l+len;mid2=r-len;
if (slope(sta[mid1],now)<slope(sta[mid2],now)) l=mid1;
else r=mid2;
}
for (int j=l;j<=r;j++) maxn=max(maxn,slope(sta[j],now));ans+=maxn;
}
printf("%.0f\n",ans);
}