洛谷傳送門
BZOJ傳送門
題目描述
邱老師是妖怪愛好者,他有只妖怪,每隻妖怪有攻擊力atk和防禦力dnf兩種屬性。邱老師立志成爲妖怪大師,於是他從真新鎮出發,踏上未知的旅途,見識不同的風景。
環境對妖怪的戰鬥力有很大影響,在某種環境中,妖怪可以降低自己點攻擊力,提升點防禦力或者,提升自己點攻擊力,降低點防禦力,,屬於正實數,爲任意實數,但是atk和dnf必須始終非負。
妖怪在環境中的戰鬥力爲妖怪在該種環境中能達到的最大攻擊力和最大防禦力之和。環境由,兩個參數定義,,的含義見前文描述。
比如當前環境,,那麼攻擊力爲,防禦力爲的妖怪,能達到的最大攻擊力爲,最大防禦力爲。所以該妖怪在,的環境下戰鬥力爲。
因此,在不同的環境,戰鬥力最強的妖怪可能發生變化。
作爲一名優秀的妖怪訓練師,邱老師想發掘每一隻妖怪的最大潛力,他想知道在最爲不利的情況下,他的只妖怪能夠達到的最強戰鬥力值,即存在一組正實數使得只妖怪在該環境下最強戰鬥力最低。
輸入輸出格式
輸入格式:
第一行一個,表示有只妖怪。
接下來行,每行兩個整數atk和dnf,表示妖怪的攻擊力和防禦力。
輸出格式:
輸出在最不利情況下最強妖怪的戰鬥力值,保留位小數。
輸入輸出樣例
輸入樣例#1:
3
1 1
1 2
2 2
輸出樣例#1:
8.0000
解題分析
題目就是要我們求下面這個式子:
設, 那麼後面那個式子就變成了。
這是個啥玩意呢? 畫出平面直角座標系可以發現這玩意就是斜率爲, 經過點的直線在和軸上的截距之和。
然後發現可能成爲最大值的點一定在一個上凸包上, 搞一搞就好。
由均值不等式可得這個函數的最小值在處取到, 這個點成爲最大值的區間就是相鄰兩條線段的斜率之間的部分, 判一判是不是在這個區間內就好了。
注意右上凸包兩端的點的橫縱座標分別加上EPS, 避免出現nan的情況。
代碼如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <iostream>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define db long double
#define MX 1000050
#define EPS 1e-8
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n, cnum;
int conv[MX];
struct Point {db x, y;}dat[MX];
IN Point operator + (const Point &x, const Point &y) {return {x.x + y.x, x.y + y.y};}
IN Point operator - (const Point &x, const Point &y) {return {x.x - y.x, x.y - y.y};}
IN db operator * (const Point &x, const Point &y) {return x.x * y.y - x.y * y.x;}
IN bool operator < (const Point &x, const Point &y) {return x.x == y.x ? x.y > y.y : x.x < y.x;}
IN db Getk(const Point &x) {return x.y / x.x;}
IN void Getconv()
{
std::sort(dat + 1, dat + 1 + n);
for (R int i = 1; i <= n; ++i)
{
W (cnum >= 2 && (dat[conv[cnum]] - dat[conv[cnum - 1]]) * (dat[i] - dat[conv[cnum - 1]]) >= 0) --cnum;
conv[++cnum] = i;
}
}
int main(void)
{
db mxx = 0, mxy = 0, ratl, ratr, best;
scanf("%d", &n);
for (R int i = 1; i <= n; ++i)
{
scanf("%Lf%Lf", &dat[i].x, &dat[i].y);
mxx = max(mxx, dat[i].x), mxy = max(mxy, dat[i].y);
}
dat[++n] = {0, mxy}, dat[++n] = {mxx, 0};
Getconv(); db ans = 1e18;
dat[conv[cnum]].x += EPS;
dat[conv[1]].y += EPS;
for (R int i = 2; i < cnum; ++i)
{
ratl = -Getk(dat[conv[i]] - dat[conv[i - 1]]);
ratr = -Getk(dat[conv[i + 1]] - dat[conv[i]]);
ans = min(ans, dat[conv[i]].x + dat[conv[i]].y + ratl * dat[conv[i]].x + dat[conv[i]].y / ratl);
ans = min(ans, dat[conv[i]].x + dat[conv[i]].y + ratr * dat[conv[i]].x + dat[conv[i]].y / ratr);
best = std::sqrt(dat[conv[i]].y / dat[conv[i]].x);
if (best >= ratl && best <= ratr) ans = min(ans, dat[conv[i]].x + dat[conv[i]].y + best * dat[conv[i]].x + dat[conv[i]].y / best);
}
printf("%.4Lf", ans);
}