Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4570
Solution
显然,对于攻击力为
,防御力为
的妖怪,在环境
下的战斗力为:
可以发现真正与妖怪战斗力有关的是 而不是 。 设 。
因此原式化为:
考虑两只妖怪,第一只的攻击力和防御力分别为 ,第二只的攻击力和防御力分别为 ( ),那么第一只妖怪的战斗力比第二只强,当且仅当:
左边是斜率的表示!
将每个妖怪看作一个点 。
如果你学过斜率优化或其他相关的东西,那么你可以看出:
所有战斗力可能最大的妖怪都在所有点组成的 上凸壳上。
设 为 上凸壳上从左到右第 个点, 为点 和点 所在直线的斜率,
那么 为战斗力最大值,当且仅当:
也就是说:
也就是说,将 正数 定义在一个区间 内,求 取何值时 最小 ,并求最小值。
显然,如果对 的值的限制只是正数,那么 时,上式取得最小值 。
因此可以分类讨论:
(1) 时, 取 。
(2) 时, 取 。
(3) 时, 取 。
特殊:如果 是上凸壳的第一个或最后一个点,那么 就没有上界限制或没有下界限制(不过 必须大于 )。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll; const int N = 1e6 + 5;
int n, top; double ans = 1e133;
struct cyx {
int x, y;
inline cyx operator - (cyx rhs) {return (cyx) {rhs.x - x, rhs.y - y};}
inline ll operator * (cyx rhs) {return 1ll * x * rhs.y - 1ll * y * rhs.x;}
inline bool operator < (cyx rhs) {
return x < rhs.x || (x == rhs.x && y > rhs.y);
}
inline double slope(cyx rhs) {
return 1.0 * (y - rhs.y) / (x - rhs.x);
}
} a[N], stk[N];
int main() {
int i; n = read(); For (i, 1, n) a[i].x = read(), a[i].y = read();
sort(a + 1, a + n + 1); For (i, 1, n) {
if (i > 1 && a[i - 1].x == a[i].x) continue;
while (top > 1 && (stk[top - 1] - stk[top]) * (stk[top - 1] - a[i]) > 0)
top--; stk[++top] = a[i];
}
For (i, 1, top) {
double l = 0, r = 1e79;
if (i > 1) l = max(l, -stk[i - 1].slope(stk[i]));
if (i < top) r = min(r, -stk[i].slope(stk[i + 1])); if (l > r) continue;
double mid = sqrt(1.0 * stk[i].x * stk[i].y) / stk[i].x;
if (r < mid) ans = min(ans,
r * stk[i].x + 1.0 * stk[i].y / r + stk[i].x + stk[i].y);
else if (l > mid) ans = min(ans,
l * stk[i].x + 1.0 * stk[i].y / l + stk[i].x + stk[i].y);
else ans = min(ans, mid * stk[i].x + 1.0 * stk[i].y / mid
+ stk[i].x + stk[i].y);
}
printf("%.4lf\n", ans); return 0;
}