Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4570
Solution
显然,对于攻击力为
A
A
,防御力为 的妖怪,在环境
(a,b)
(
a
,
b
)
下的战斗力为:
A+abB+B+baA
A
+
a
b
B
+
B
+
b
a
A
可以发现真正与妖怪战斗力有关的是 ba b a 而不是 (a,b) ( a , b ) 。 设 x=ba x = b a 。
因此原式化为:
A+1xB+B+Ax=(1+x)A+1+xxB
A
+
1
x
B
+
B
+
A
x
=
(
1
+
x
)
A
+
1
+
x
x
B
考虑两只妖怪,第一只的攻击力和防御力分别为 A,B A , B ,第二只的攻击力和防御力分别为 C,D C , D ( A>C A > C ),那么第一只妖怪的战斗力比第二只强,当且仅当:
(1+x)A+1+xxB>(1+x)C+1+xxD
(
1
+
x
)
A
+
1
+
x
x
B
>
(
1
+
x
)
C
+
1
+
x
x
D
(1+x)A−(1+x)C>1+xxD−1+xxB
(
1
+
x
)
A
−
(
1
+
x
)
C
>
1
+
x
x
D
−
1
+
x
x
B
D−BA−C<x
D
−
B
A
−
C
<
x
B−DA−C>−x
B
−
D
A
−
C
>
−
x
左边是斜率的表示!
将每个妖怪看作一个点 (atk,dnf) ( a t k , d n f ) 。
如果你学过斜率优化或其他相关的东西,那么你可以看出:
所有战斗力可能最大的妖怪都在所有点组成的 上凸壳上。
设 Pi P i 为 上凸壳上从左到右第 i i 个点, 为点 X X 和点 所在直线的斜率,
那么 Pi P i 为战斗力最大值,当且仅当:
slope(Pi+1,Pi)≤−x≤slope(Pi,Pi−1)
s
l
o
p
e
(
P
i
+
1
,
P
i
)
≤
−
x
≤
s
l
o
p
e
(
P
i
,
P
i
−
1
)
也就是说:
−slope(Pi,Pi−1)≤x≤−slope(Pi+1,Pi)
−
s
l
o
p
e
(
P
i
,
P
i
−
1
)
≤
x
≤
−
s
l
o
p
e
(
P
i
+
1
,
P
i
)
也就是说,将 正数 x x 定义在一个区间 内,求 x x 取何值时 最小 ,并求最小值。
显然,如果对 x x 的值的限制只是正数,那么 时,上式取得最小值 2AB−−−√ 2 A B 。
因此可以分类讨论:
(1) r<AB√A r < A B A 时, x x 取 。
(2) l>AB√A l > A B A 时, x x 取 。
(3) l≤AB√A≤r l ≤ A B A ≤ r 时, x x 取 。
特殊:如果 Pi P i 是上凸壳的第一个或最后一个点,那么 x x 就没有上界限制或没有下界限制(不过 必须大于 0 0 <script type="math/tex" id="MathJax-Element-5149">0</script> )。
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;
}