DUATHLON (중, p. 483)

문제#

image.png


어떻게 풀었나?#

T = “0~n-2번째 중 가장 빨리 완주하는데 걸리는 시간” - “n-1번째(cheater)가 완주하는데 걸리는 시간”

T를 위와 같이 정의할 때, T값이 가장 최대가 되는 지점을 삼분 탐색(ternary search)을 통해 찾았다.


정답 코드#

#include <bits/stdc++.h>
using namespace std;
int n,t;
double a[21],b[21];
double f(double x) {
    double res=(1/a[0])*x + (1/b[0])*(t-x);
    for(int i=1; i<n-1; i++) {
        res = min(res, (1/a[i])*x + (1/b[i])*(t-x));
    }
    return res - (1/a[n-1]*x + 1/b[n-1]*(t-x));
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int tc;
    while(cin >> t) {
        cin >> n;
        for(int i=0; i<n; i++) {
            cin >> a[i] >> b[i];
        }

        double lo=0, hi=t;
        for(int i=0; i<100; i++) {
            double l=(lo*2+hi)/3;
            double r=(lo+hi*2)/3;
            double fl = f(l);
            double fr = f(r);
            if(fr<fl) hi=r;
            else lo=l;
        }

        double ans = (lo+hi)/2;
        double fans = f(ans);

        if(fans < -1e-9) puts("The cheater cannot win.");
        else {
            if(fans<0) fans=0;
            int ifans = round(fans*3600.0);
            printf("The cheater can win by %d seconds with r = %.2lfkm and k = %.2lfkm.\n", ifans, ans, t - ans);
        }
    }
    return 0;
}

Comment#

이 문제는 오차 관련해서 잘 처리해줘야 했다. AC받기 전 수도없이 많은 WA를 받았는데, 이유는 2가지였다. 하나는 fans*3600을 한 다음에 반올림 처리를 해야했는데 하지 않았던 것이었고, 다른 하나는 fans값에 대한 오차 처리였다. 동시간으로 우승하는 경우 fans값을 0으로 만들어야 했는데, 이게 소수 연산이다보니 부정확해서 아주 작은 음수의 경우도 0으로 처리해야하는 문제가 있었다.

아래 스샷은 고통의 흔적. 왜맞틀!

image1.png