[Problem Description]
![](http://www.lydsy.com/JudgeOnline/upload/201305/1%2813%29.jpg)
[Algorithm]
凸包 三分
[Analysis]
题目看着非常蛋疼,但是只要读懂了题目,题意还是非常简洁明了的。设sum[i]为前i天所有僵尸的血量和。则由题意可得第i天植物塔防的攻击最小值
f[i] = max((s[i] - s[j - 1]) / (x[i] + d * i - d * j)) 1 <= j <= i
可以把f[i]看成是(d * j, s[j - 1]) 与 (x[i] + d * i, s[i])的连线的斜率。由于做i的决策的时候,(x[i] + d * i, s[i])是一个定点并且这个点一定在所以用来提供决策的点的右面,所以要选取的点一定在下凸壳上。由于d * j是单调的,所以可以用一个单调栈来维护下凸壳。然后通过三分来找最大的斜率。
[Pay Attention]
1.精度问题……刚开始设了一个EPS到1e-5结果挂了……改成long double
2.三分……没大写过三分结果不是死循环就是wa……整数三分要这样写:
while (left + 1 < right)
{
int lmid = left - 1 + (right - left + 1) / 3;
int rmid = left - 1 + (right - left + 1) * 2 / 3;
if (-----)
left = lmid + 1;
else
right = rmid - 1;
}
ans = max(--[left], --[right]);
[Code]
/**************************************************************
Problem: 3203
User: gaotianyu1350
Language: C++
Result: Accepted
Time:496 ms
Memory:4432 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
using namespace std;
const long double EPS = 1e-15;
const long long MAXN = 101000;
long long st[MAXN] = {0}, top = 0;
long long sum[MAXN] = {0}, x[MAXN], a[MAXN];
long long d, n;
inline long double dmax(long double a, long double b)
{
return a > b ? a : b;
}
inline long double xie(long long i, long long j)
{
long long X1 = d * i;
long long Y1 = sum[i - 1];
long long X2 = d * j;
long long Y2 = sum[j - 1];
return (long double)(Y1 - Y2) / (X1 - X2);
}
inline long double calc(long long i, long long j)
{
return (long double)(sum[i] - sum[j - 1]) / (x[i] + d * i - d * j);
}
inline long long dcmp(long double a, long double b)
{
if (fabs(a - b) < EPS) return 0;
return a > b ? 1 : -1;
}
int main()
{
scanf("%lld%lld", &n, &d);
for (long long i = 1; i <= n; i++)
{
scanf("%lld%lld", &a[i], &x[i]);
sum[i] = sum[i - 1] + a[i];
}
long double ans = 0;
for (long long i = 1; i <= n; i++)
{
while (top > 1 && dcmp(xie(i, st[top]), xie(st[top], st[top - 1])) <= 0)
top--;
st[++top] = i;
long long left = 1, right = top;
while (left + 1 < right)
{
long long t = (right - left + 1) / 3;
long long l = left - 1 + t;
long long r = l + t;
long double lans = calc(i, st[l]);
long double rans = calc(i, st[r]);
if (dcmp(lans, rans) < 0)
left = l + 1;
else
right = r - 1;
}
ans += dmax(calc(i, st[left]), calc(i, st[right]));
}
printf("%.0f\n", (double)ans);
}