mayoko’s diary

プロコンとかいろいろ。

東京大学プログラミングコンテスト2013 D - 壊れかけのヒープ

解法

N <= 100 と制約が結構ゆるいので, 「m <= 1000 くらいまでヒープの大きさを試して, 配列の大きさが m で valid になるなら m を返す」みたいな感じでやれば OK です。valid になるかどうかの判定は, 「まだ配列に入っていない数のうち, 入れることが出来る数値」を後ろから貪欲に入れていけば良いです。

const int INF = 1e9+7;

bool ok(const vector<int>& A, int m) {
    int n = A.size();
    set<int> S;
    vector<int> B(m+1, INF);
    for (int i = 0; i < n; i++) {
        B[m-n+i] = A[i];
        S.insert(A[i]);
    }
    for (int i = m-1; i >= 1; i--) {
        int tar = 0;
        int ptr = (i-1)/2;
        if (i%2) {
            tar = min(B[i], B[i+1]) - 1;
        } else {
            tar = min(B[i], B[i-1]) - 1;
        }
        if (B[ptr] < INF) {
            if (B[ptr] > tar) return false;
            continue;
        }
        while (tar >= 0) {
            if (S.find(tar) == S.end()) break;
            tar--;
        }
        if (tar < 0) return false;
        S.insert(tar);
        B[ptr] = tar;
    }
    return true;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N;
    cin >> N;
    vector<int> A(N);
    for (int i = 0; i < N; i++) cin >> A[i];
    for (int i = N; i < 1000; i++) {
        if (ok(A, i)) {
            cout << i << endl;
            return 0;
        }
    }
    cout << -1 << endl;
    return 0;
}