• BZOJ4570: [Scoi2016]妖怪


    题目传送门

    4570: [Scoi2016]妖怪

    Time Limit: 10 Sec Memory Limit: 64 MB

    Submit: 491 Solved: 125

    [Submit][Status][Discuss]

    Description

    邱老师是妖怪爱好者,他有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只妖怪在该环境下最强战斗力最低。

    Input

    第一行一个n,表示有n只妖怪。接下来n行,每行两个整数atk和dnf,表示妖怪的攻击力和防御力。
    1≤n≤10^6, 0<atk,dnf≤10^8

    Output

    输出在最不利情况下最强妖怪的战斗力值,保留4位小数。

    Sample Input

    3

    1 1

    1 2

    2 2

    Sample Output

    8.0000

    题解

    首先我们可以得到 $strength= atk + a / b * dnf + dnf + b / a * atk $ ,进而得到 (strength=(a+b)/a*atk+(a+b)/b * dnf)
    所以我们将atk看为x,dnf看为y,则strength就是一条斜率为$ -b/a $ 的直线,而此时最大战力就是就是最外面的那条直线。所以我们可以将这些直线跑一个半凸包。其实按照我的想法就该三分了,然出题人告诉我这样会挂。。。

    正解是这些点些点对应的斜率都有一个范围,然后将 (strength) 变为一个双钩函数,之后讨论最值,跟新ans。

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    LL Ina; bool InSign; char Inc;
    inline LL geti() {
    	InSign = false; 
            while ((Inc = getchar()) < '0' || Inc > '9') InSign |= Inc == '-'; 
            Ina = Inc - '0';
    	while ((Inc = getchar()) >= '0' && Inc <= '9') Ina = (Ina << 3) + (Ina << 1) + Inc - '0'; 
            return InSign ? -Ina : Ina;
    }
    const int N = 1e6 + 5;
    const double OO = 1e9;
    struct P{
    	LL x, y;
    	P(LL a = 0, LL b = 0) : x(a), y(b) {}
    	P operator - (const P &a) const { return P(x - a.x, y - a.y); }
    	LL operator * (const P &a) const { return x * a.y - y * a.x; }
    	bool operator < (const P &a) const { return (x < a.x) || (x == a.x && y < a.y); }
    	void Read() { x = geti(), y = geti(); }
    }p[N], Stack[N];
    //k = -b/a
    inline double get(const P &a) { return -sqrt((double)a.y / a.x); }
    inline double getk(const P &a, const P &b) { 
           return (a.x ^ b.x) ? ((double)(a.y - b.y) / (double)(a.x - b.x)) : OO; 
    }
    inline double Cal(const P &a, const double &k) { 
           return k >= 0 ? OO : (double)a.x + a.y + - k * a.x - a.y / k; 
    }
    template <class T>
    inline void SelfMin(T &a, const T &b) { if (b < a) a = b; }
    
    int main() {
    	int n = geti(), i, j, top = 0;
    	for (i = 1; i <= n; ++i) p[i].Read();
    	sort(p + 1, p + n + 1);
    	Stack[++top] = p[1];
    	for (i = 2; i <= n; ++i) {
    		while (top >= 2 && (Stack[top]-Stack[top-1])*(p[i]-Stack[top-1]) >= 0) 
                        --top;
    		Stack[++top] = p[i];
    	}
    	if (top < 2) return printf("%.4lf
    ", Cal(Stack[1], get(Stack[1]))), 0;
    	double k, k1, k2, ans = OO;
    	k2 = getk(Stack[1], Stack[2]); k = get(Stack[1]);
    	if (k >= k2) SelfMin(ans, Cal(Stack[1], k));
    	k1 = getk(Stack[top - 1], Stack[top]); k = get(Stack[top]);
    	if (k <= k1) SelfMin(ans, Cal(Stack[top], k));
    	SelfMin(ans, Cal(Stack[top], k1));
    	for (i = 2; i < top; ++i) {
    		k1 = getk(Stack[i - 1], Stack[i]), k2 = getk(Stack[i], Stack[i + 1]);
                    k = get(Stack[i]);
    		SelfMin(ans, Cal(Stack[i], k1));
    		if ((k <= k1) && (k >= k2)) SelfMin(ans, Cal(Stack[i], k));
    	}
    	return printf("%.4lf
    ", ans), 0;
    }
    
  • 相关阅读:
    自控力和专注力是执行力的保证
    今宵又除夕
    买了小米盒子三代
    电容相位滞后?电感超前
    lcr电桥浅谈
    ad 线束和网络
    浅谈 R_S触发器
    NTSC PAL 介绍
    verilog 之流水灯
    io 口方向调整 stm32
  • 原文地址:https://www.cnblogs.com/cycleke/p/5838884.html
Copyright © 2020-2023  润新知