模擬国内2017C: クイズ

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2825

問題

参加者 n人、問題数 m問のクイズ大会を考える。また、 i問目の問題の得点は s_iである。
このクイズ大会では、 i問目に正解する可能性がある参加者が k_i人おり、それぞれ c_iであることがわかっている。
この設定で、 m+1問目の得点をその時点でどのような得点状況でも正解すれば逆転できるように設定する。
そのような得点の最小値を出力する。

解法

それぞれの人に対して、その人が取り得る得点の最小値と最大値を計算しておく。
そのような配列を ma,  miとして、あわせて誰の得点なのかも保持しておく。
計算方法としては、

  • 最小 → 出来るだけ正解しない、候補が自分1人のときはしょうがないので正解する。
  • 最大 → 出来るだけ正解する。

を愚直にやれば良い。

最後に Max\{ma\} - Min\{mi\} + 1とすれば答えが出るのだが、最大値と最小値の保持者が同じときに注意が必要であり、 このとき、 Max \{ ma[0] - mi[1], ma[1] - mi[0] \} + 1 のようにする必要がある。

コード

http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=4896138#1

int n, m;

void solve() {
    using P = pair<int, int>;

    vector<P> ma(n), mi(n);
    for (int i = 0; i < m; i++) {
        int s, k;
        cin >> s >> k;
        for (int j = 0; j < k; j++) {
            int id; cin >> id;
            if (k == 1) mi[id-1].first += s;
            ma[id-1].first += s;
        }
    }

    for (int i = 0; i < n; i++) {
        ma[i].second = i;
        mi[i].second = i;
    }

    sort(ma.rbegin(), ma.rend());
    sort(mi.begin(), mi.end());

    int ans = ma[0].first - mi[0].first;
    if (ma[0].second == mi[0].second) {
        //ここはmaxです(戒め)
        ans = max(ma[0].first - mi[1].first, ma[1].first - mi[0].first);
    }

    cout << ans + 1 << endl;
}