[BZOJ3203][SDOI2013][凸包][三分]保护出题人

来源:互联网 发布:java 隐式参数 编辑:程序博客网 时间:2024/05/16 00:37
[Problem Description]

[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);   }




0 0