【LOJ】 #2015. 「SCOI2016」妖怪

题解

这道题教会我很多东西,虽然它是个傻逼三分
1.long double的运算常数是巨大的
2.三分之前的界要算对!一定要算准,不要想一个直接写上!
3.三分100次也就只能把精度往里推20多位,可你需要的精度是最大数值加小数位,大概是12位,而你三分的界最小也得卡到1e4和1e-4(虽然,用1e3和1e-3作为界也能过,我可不想考场上赌这个东西= =),精度爆炸……如何优化……
(其实atk和dnf小一点能更不卡精度吧= =)
(这样的题根本连调都调不出来,就算我界算对了也得被三分次数卡死= =)
好的我们来说这道题
首先思路很明显,我们可以推一只妖怪的攻击力的表达式
\(\frac{a}{b}dnf + \frac{b}{a}atk + atk + dnf\)
我们设\(k = \frac{b}{a}\)
那么\(atk \cdot k + dnf \frac{1}{k} + atk + dnf\)我们发现这是一个对勾函数
啥,你说你不知道什么是对勾函数数学课是不是又逃课了
(自行描点画一下\(k + \frac{1}{k}\))
这个东西在第一象限的图像是个单峰函数,这样n个单峰函数复合在一起求最大值还是一个单峰函数,可以三分
复杂度\(O(n \log_3 n)\)
鉴于我死的很惨,我讲讲怎么算界
首先这个东西要取到最小值的话大概是
\(atk \cdot k = dnf \frac{1}{k}\)可以得出k大概是根号下dnf和atk的比值,大概是1e-4到1e4
然而你即使三分90次还是会跪
仗着LOJ很快我三分了100次……过掉了
其实1e3也能AC但是= =这会被非常极限的数据卡死,完全就是赌出题人到底善不善良

代码

#include <bits/stdc++.h>
//#define ivorysi
#define MAXN 1000005
typedef long long int64;
typedef unsigned int u32;
using namespace std;
const int MOD = 1000000007;
int n;
double atk[MAXN],dnf[MAXN];
double calc(double k) {
    double res = 0.0;
    for(int i = 1 ; i <= n ; ++i) {
    res = max(res,atk[i] + dnf[i] + k * atk[i] + (1.0 / k) * dnf[i]);
    }
    return res;
}
void Solve() {
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; ++i) {
    scanf("%lf%lf",&atk[i],&dnf[i]);
    }
    int cnt = 100;
    double l = 1e-4,r = 1e4;
    while(cnt--) {
    double k = (r - l) / 3.0;
    double lb = l + k,rb = r - k;
    if(calc(lb) > calc(rb)) l = lb;
    else r = rb;
    }
    printf("%.4lf",calc(r));
}

int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

猜你喜欢

转载自www.cnblogs.com/ivorysi/p/9155819.html
今日推荐