• bzoj 3203: [Sdoi2013]保护出题人 凸包


    题目大意:

    http://www.lydsy.com/JudgeOnline/problem.php?id=3203

    题解

    首先我们考虑对一大波僵尸来袭的情况进行分析
    假设来袭的僵尸是({ a_1,a_2,a_3,...,a_n})
    那么距离分别为({dis,dis+d,dis+d*2,...,dis+d*(n-1)})
    那么我们知道,在这波僵尸中,我们应该取到的最小的攻击速度为
    (max{frac{sum_i}{dis_i}})
    其中(sum_n = sum_{i=1}^{n}a_i,dis_i = dis + (i-1)*d)
    然后我们把这个式子转化到原序列中,发现式子变成了下面这个样子
    假设排头的僵尸是(p) :
    那么有(ans_p = max_{i=1}^n{frac{sum_p - sum_{i-1}}{(dis_p+p*d - i*d)}})
    而我们的目的就是最小化(sum_{i=1}^nans_i)
    我们观察上面关于(ans_p)的式子,发现这实际上是两个点的斜率
    ((dis_p+p*d,sum_p))((i*d,sum_{i-1}))两个点的斜率
    所以我们枚举每个p,然后对于每个p都计算出所有的((i*d,sum_{i-1}))
    然后再取斜率最大值即可...
    TLE
    我们发现每次针对不同的p计算的时候((i*d,sum_{i-1}))居然都是相同的!
    所以我们根本不需要每次都重新计算
    那么每次当我们枚举到一个p的时候,计算所有满足(ileq p)的点中与其最大斜率即可
    那怎么计算这个最大斜率呢??
    我们知道每次加入的点在横纵坐标上一定都比上一次加入的点要大
    说起来比较矛盾,但是我们需要维护一个不会将任何点包括的"上凸壳"
    然后在这个"上凸壳"上的斜率明显是一个单峰函数,所以我们三分即可.

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline void read(ll &x){
        x=0;char ch;bool flag = false;
        while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
        while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
    inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
    const int maxn = 100010;
    const double eps = 1e-9;
    inline int dcmp(const double &x){
        if(x < eps && x > -eps) return 0;
        return x > 0 ? 1 : -1;
    }
    struct Point{
        double x,y;
        Point(const double &a = 0,const double &b = 0){x=a;y=b;}
        void print(){
            printf("Point : (%lf,%lf)
    ",x,y);
        }
    };
    typedef Point Vector;
    inline Vector operator + (const Vector &a,const Vector &b){
        return Vector(a.x+b.x,a.y+b.y);
    }
    inline Vector operator - (const Vector &a,const Vector &b){
        return Vector(a.x-b.x,a.y-b.y);
    }
    inline double cross(const Vector &a,const Vector &b){
        return a.x*b.y - a.y*b.x;
    }
    inline double slope(const Point &a,const Point &b){
        return (a.y - b.y)/(a.x - b.x);
    }
    Point p[maxn];int m = 0;
    inline void insert(const Point &x){
        while(m > 1 && dcmp(cross(p[m] - p[m-1],x - p[m])) <= 0) -- m;
        p[++m] = x;
    }
    ll a[maxn],dis[maxn],sum[maxn];
    double solve(const Point &x){
        int l = 1,r = m,midx,midy;
        while(l <= r-3){
            midx = (l+l+r)/3;midy = (l+r+r)/3;
            if(slope(p[midx],x) > slope(p[midy],x)) r = midy;
            else l = midx;
        }
        double ans = .0;
        for(int i=l;i<=r;++i) ans = max(ans,slope(p[i],x));
        return ans;
    }
    int main(){
        ll n,d;read(n);read(d);
        for(int i=1;i<=n;++i){
            read(a[i]);read(dis[i]);
            sum[i] = sum[i-1] + a[i];
        }double ans = .0;
        for(int i=1;i<=n;++i){
            insert(Point(i*d,sum[i-1]));
            ans += solve(Point(dis[i]+i*d,sum[i]));
        }printf("%.0f
    ",ans);
        getchar();getchar();
        return 0;
    }
    
  • 相关阅读:
    伐木工和森林的故事(一)
    EclipsePDT PHP的开发环境配置
    奇怪的using
    [团队开发]SERVER2008下无法安装VS2008 SP1 和 TFS2008 SP1补丁
    写在七夕
    一点点的松懈,就可以毁掉自己!
    2008,到今天我不后悔
    细节决定成败,注意的事情需要做到,而不是听完了当耳边风
    正视差距,展望2008!
    ZendStudio5.5调式环境配置
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6435544.html
Copyright © 2020-2023  润新知