第3回 ドワンゴからの挑戦状 予選: D - ネタだけ食べたい寿司

,

http://dwacon2017-prelims.contest.atcoder.jp/tasks/dwango2017qual_d

$4.5$完早解きしたので$21$位だった。順位表$1$ページ目からは落ちた。threepipesさんが以前のDDCC参加者内での順位を出してくれており、見ると$9$位なのでその他枠通過の可能性がある。

solution

$M$回目にネタだけを食べる位置について全て見る。$O(N \log N)$。

寿司$i$で$M$回目のネタだけを食べるとしよう。 寿司$j \lt i$について、$X_j - Y_j$が大きい順に$M-1$個をネタだけで食べ、その他は普通に食べるのがよい。 このような食べ方の際の値は、$i$を$0$から$N-1$まで動かしながらpriority queueで管理すればそれぞれ求まる。

ネタだけを食べる回数が$M$回未満である場合は考慮しなくてよい。列の末尾で自明にネタだけが有利であるため。

implementation

#include <iostream>
#include <vector>
#include <numeric>
#include <queue>
#define repeat(i,n) for (int i = 0; (i) < int(n); ++(i))
#define whole(f,x,...) ([&](decltype((x)) whole) { return (f)(begin(whole), end(whole), ## __VA_ARGS__); })(x)
typedef long long ll;
using namespace std;
template <class T> using reversed_priority_queue = priority_queue<T, vector<T>, greater<T> >;
template <class T> void setmax(T & a, T const & b) { if (a < b) a = b; }
int main() {
    int n, m; cin >> n >> m;
    vector<int> x(n), y(n); repeat (i,n) cin >> x[i] >> y[i];
    vector<int> y_acc; whole(partial_sum, y, back_inserter(y_acc));
    int ans = 0;
    reversed_priority_queue<int> que;
    int acc = 0;
    repeat (i,n) {
        if (que.size() > m-1) {
            acc -= que.top();
            que.pop();
        }
        que.push(x[i] - y[i]);
        acc += x[i] - y[i];
        setmax(ans, y_acc[i] + acc);
    }
    cout << ans << endl;
    return 0;
}