AtCoder Grand Contest 008: D - K-th K

,

http://agc008.contest.atcoder.jp/tasks/agc008_d

レート持ってかれた。

反省

Cまでで時間使いすぎに焦りが加わって間に合わず。

solution

貪欲に埋める。$O(N)$。

各$i$について、$x_i$の左に$i-1$個、右に$n-i$個置けばよい。 最も左の項$a_1$を何にすべきか考えると、$x_i$の値が最も小さい$i$にするのが妥当。 そうでなく$j \ne i$にしないと失敗するとすると、$a_1$から$x_j$までまったく余裕がないことになるが、これを$x_i$の取り方と合わせるといずれにせよ失敗する。 $a_2$以降も同様に、(まだ$x_i$の左に$i-1$個置いてないような$i$の中で)$x_i$の値が最も小さい$i$にするのが妥当。 このようにして置けば左に$i-1$個の制約が満たされる。これを満たした後逆向きに同様にすれば、右に$n-i$個の制約も満たされ$a$が構成される。

implementation

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cassert>
#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)
using namespace std;
int main() {
    // input
    int n; cin >> n;
    vector<int> x(n); repeat (i,n) { cin >> x[i]; -- x[i]; }
    // solve
    vector<int> a(n*n, -1);
    repeat (i,n) a[x[i]] = i;
    vector<int> ix(n);
    whole (iota, ix, 0);
    whole (sort, ix, [&](int i, int j) { return x[i] < x[j]; });
    int j = 0;
    for (int i : ix) {
        for (int k = 0; k < i; ) {
            assert (j < n*n);
            if (a[j] == -1) {
                a[j] = i;
                ++ k;
            } else if (a[j] == i) {
                a.clear();
                goto done;
            }
            ++ j;
        }
    }
    whole(reverse, ix);
    j = n*n-1;
    for (int i : ix) {
        for (int k = 0; k < n-i-1; ) {
            assert (j >= 0);
            if (a[j] == -1) {
                a[j] = i;
                ++ k;
            } else if (a[j] == i) {
                a.clear();
                goto done;
            }
            -- j;
        }
    }
done: ;
    // output
    if (a.empty()) {
        cout << "No" << endl;
    } else {
        cout << "Yes" << endl;
        repeat (i,n*n) {
            if (i) cout << ' ';
            cout << a[i] + 1;
        }
        cout << endl;
    }
    return 0;
}