【BZOJ4570】 [Scoi2016]妖怪
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
1 1
1 2
2 2
Sample Output
8.0000
Solution
这题好像很多种做法。下面介绍一种。
凸包。
对于一个固定的k,那么a,b的取值范围是在一条第一象限的线段上。而最大化的目标其实就是这条线段和x,y轴的截距之和。
那么可以证明,能贡献答案的点一定在上凸壳上。对于凸包上的每一个点,考虑用前后的两条直线去截它然后贡献答案。对于在中间的直线可以通过计算得出最优解。
(计算过程因为这里不是markdown编辑器公式不是那么好打所以就不推了,大概就是把直线方程设出来,根据直接过(a,b)点这个条件然后消掉一个未知量,最后把最大化的东西写出来发现可以用基本不等式啥的搞一搞就好了)
Code
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 5 #define R register 6 #define maxn 1000010 7 #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0) 8 typedef double db; 9 struct Poi { 10 db x, y; 11 inline bool operator < (const Poi &that) const {return x < that.x || (x == that.x && y < that.y);} 12 inline Poi operator - (const Poi &that) const {return (Poi) {x - that.x, y - that.y};} 13 inline db operator * (const Poi &that) const {return x * that.y - y * that.x;} 14 } p[maxn], st[maxn]; 15 db slope(R Poi x) {return x.y / x.x;} 16 int main() 17 { 18 // freopen("in.in", "r", stdin); 19 R int n; scanf("%d", &n); 20 for (R int i = 1; i <= n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y); 21 std::sort(p + 1, p + n + 1); 22 st[1] = p[1]; R int top = 1; 23 for (R int i = 2; i <= n; ++i) 24 { 25 while (top > 1 && (p[i] - st[top - 1]) * (st[top] - st[top - 1]) <= 0) --top; 26 st[++top] = p[i]; 27 } 28 R db ans = 1.0 / 0.0; 29 for (R int i = 1; i <= top; ++i) 30 { 31 R db lef = i == 1 ? 0 : slope(st[i] - st[i - 1]); 32 R db rig = i == top ? -1.0 / 0.0 : slope(st[i + 1] - st[i]); 33 R db k = -sqrt(slope(st[i])); 34 if (lef >= k && k >= rig) 35 cmin(ans, st[i].x + st[i].y - k * st[i].x - st[i].y / k); 36 if (i > 1) 37 { 38 k = slope(st[i] - st[i - 1]); 39 cmin(ans, st[i].x + st[i].y - k * st[i].x - st[i].y / k); 40 } 41 } 42 printf("%.4lf\n", ans); 43 return 0; 44 }