• BZOJ 4570: [Scoi2016]妖怪 (三分 || 凸包)


    题目: BZOJ传送门

    题目:洛谷传送门

    题意:

    邱老师有n只妖怪,每只妖怪有攻击力atk和防御力dnf两种属性。在某种环境中,妖怪可以降低自己k×a点攻击力,提升k×b点防御力或者,提升自己k×a点攻击力,降低k×b点防御力,a,b属于正实数,k为任意实数,但是atk和dnf必须始终非负。妖怪在环境(a,b)中的战斗力为妖怪在该种环境中能达到的最大攻击力和最大防御力之和。strength(a,b)=max(atk(a,b))+max(dnf(a,b))环境由a,b两个参数定义,a,b的含义见前文描述。比如当前环境a=3,b=2,那么攻击力为6,防御力为2的妖怪,能达到的最大攻击力为9,最大防御力为6。所以该妖怪在a=3,b=2的环境下战斗力为15。因此,在不同的环境,战斗力最强的妖怪可能发生变化。他想知道在最为不利的情况下,他的n只妖怪能够达到的最强战斗力值,即存在一组正实数(a,b)使得n只妖怪在该环境下最强战斗力最低。
     
    输入
    第一行一个n,表示有n只妖怪。接下来n行,每行两个整数atk和dnf,表示妖怪的攻击力和防御力。
    1≤n≤10^6, 0<atk,dnf≤10^8
     
    输出
    输出在最不利情况下最强妖怪的战斗力值,保留4位小数。
     
     
     
    思路一:三分
    这题非常卡精度卡常,太恶心了
    三分一下 a/b,那么最大的攻击就是 ( 1 + a/b ) * atk,最大的防御就是 ( 1 + b/a ) * dnf
    三分代码参考了 ->
     
    不用快读就会超时,太恶心了。
    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    using namespace std;
    
    const int N = 1e6 + 5;
    const double eps = 1e-8;
    
    int a[N], b[N];
    
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    
    int dcmp(double x) {
        if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;
    }
    
    double cal(double mid, int n) {
        double ma = 0.0;
        rep(i, 1, n) {
            ma = max(ma, a[i] * (1 + mid) + b[i] * (1 + 1 / mid));
        }
        return ma;
    }
    
    int main() {
        int n;
        n = read();
    
        rep(i, 1, n) a[i] = read(), b[i] = read();
    
        double l = eps, r = 1 / eps;
    
        while(l + 1E-6 <= r) {
    
            double midl = (l + r) / 2.0 - eps;
            double midr = (l + r) / 2.0 + eps;
    
            if(cal(midl, n) < cal(midr, n)) {
                r = midr;
            }
            else {
                l = midl;
            }
        }
    
        rep(i, 1, 35) {
            double midl = l + (r - l) / 3.0;
            double midr = r - (r - l) / 3.0;
            if(cal(midl, n) < cal(midr, n)) r = midr;
            else l = midl;
        }
    
        printf("%.4f
    ", cal(l, n));
    
        return 0;
    }
    View Code

     

     思路二:凸包

     思路参考:Go

    代码参考:Go

     

     这里加一点自己的理解:

    1、最大值在凸包的右上部分,因为这部分的 x 和 y 都是最大的。

    2、这个点成为最大值的 k 的区间就是相邻两条线段的斜率之间部分,所以因为 k 若不在这部分,它不能成为最大值,所以不能用它来更新答案。

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    using namespace std;
    
    const int N = 1e6 + 5;
    const double eps = 1e-8;
    
    struct Point {
        double x, y;
        Point(double x = 0, double y = 0) : x(x), y(y) { }
    };
    
    int dcmp(double x) {
        if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;
    }
    
    Point operator + (Point A, Point B) { return Point(A.x + B.x, A.y + B.y); }
    Point operator - (Point A, Point B) { return Point(A.x - B.x, A.y - B.y); }
    Point operator * (Point A, double p) { return Point(A.x * p, A.y * p); }
    Point operator / (Point A, double p) { return Point(A.x / p, A.y / p); }
    double Cross(Point A, Point B) { return A.x * B.y - A.y * B.x; }
    bool operator < (Point A, Point B) { return A.x < B.x || (A.x == B.x && A.y < B.y); }
    
    int ConvexHull(Point* p, int n, Point* ch) {
        sort(p, p + n);
        int m = 0;
        ch[++m] = p[0];
        rep(i, 1, n - 1) {
            while(m >= 0 && dcmp(Cross(ch[m] - ch[m - 1], p[i] - ch[m])) >= 0) m--;
            ch[++m] = p[i];
        }
        return m;
    }
    
    Point P[N], Q[N];
    
    int main() {
    
        int n;
        scanf("%d", &n);
        rep(i, 0, n - 1) scanf("%lf %lf", &P[i].x, &P[i].y);
    
        n = ConvexHull(P, n, Q);
    
        double ans = 12345678900.0;
    
        rep(i, 1, n) {
            double nowk = -(sqrt(Q[i].y) / sqrt(Q[i].x));
            double prek = (i - 1 > 0 ? ((Q[i - 1].y - Q[i].y) / (Q[i - 1].x - Q[i].x)) : 0);
            double nxtk = (i + 1 <= n ? ((Q[i].y - Q[i + 1].y) / (Q[i].x - Q[i + 1].x)) : -12345678900.0);
            if(nowk > prek) ans = min(ans, Q[i].x * (1 - prek) + Q[i].y * (1 - 1/prek));
            else if(nowk < nxtk) ans = min(ans, Q[i].x * (1 - nxtk) + Q[i].y * (1 - 1/nxtk));
            else ans = min(ans, Q[i].x * (1 - nowk) + Q[i].y * (1 - 1/nowk));
        }
    
        printf("%.4f
    ", ans);
    
        return 0;
    }
    View Code
    一步一步,永不停息
  • 相关阅读:
    笔试:一个逻辑题
    jmeter,学这些重点就可以了
    性能测试:通过一个案例(等待锁超时)告诉你,性能到底要不要熟悉业务逻辑?
    源码解读:webdriver client的原理 (面试自动化:如果你认为知道18种定位方式就算会自动化,那就太low了)
    测试必备:jmeter测试http协议接口的各种传参方式
    Vue笔记:封装 axios 为插件使用
    Vue笔记:使用 axios 发送请求
    Tomcat笔记:Tomcat的执行流程解析
    Git笔记:Git介绍和常用命令汇总
    Spring Boot使用Shiro实现登录授权认证
  • 原文地址:https://www.cnblogs.com/Willems/p/12497005.html
Copyright © 2020-2023  润新知