mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #204 (Div. 1) A. Jeff and Rounding

Codeforces Round #204 (Div. 1) の練習会に参加しました。今回は B < A < C という難易度だった感じがする。

解法

まず, 各実数の整数部分は関係ないのでそぎ落としましょう。すると, 基本的には ai の床関数を取ることは ai に対応する整数として 0 を取ることに, ai の天井関数を取ることは ai に対応する整数として 1 を取ることになります。ただ例外があって, ai が 0 の場合は, 床関数を取ろうが天井関数を取ろうが ai に対応する整数は 0 を取ることになります。

よって, 各 ai に対応する整数として 1 を取るか 0 を取るかの自由度が ai == 0 となる小数の数分だけ出来てこれについて「整数部分の和」と「小数部分の和」の差の絶対値を最小化しよう, という問題になります。

ai == 0 となる小数の数(cnt とする)が n 以下の場合, 整数部分の和は実質的に n-cnt から n 個まで取ることが出来ます。
また, cnt > n の場合, 整数部分の和は実質的に 0 から 2*n-cnt 個まで取ることが出来ます。

const int MAXN = 4040;
double A[MAXN];

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    int cnt = 0;
    double sum = 0;
    for (int i = 0; i < 2*n; i++) {
        cin >> A[i];
        double tmp, y;
        y = modf(A[i], &tmp);
        if (y == 0) cnt++;
        sum += y;
    }
    if (cnt <= n) {
        double ans = 1e9;
        for (int i = n-cnt; i <= n; i++) {
            ans = min(ans, abs(sum-i));
        }
        printf("%.3lf\n", ans);
    } else {
        double ans = 1e9;
        int a, b;
        for (int i = 0; i <= 2*n-cnt; i++) {
            ans = min(ans, abs(sum-i));
        }
        printf("%.3lf\n", ans);
    }
    return 0;
}