mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #Pi (Div. 2) D. One-Dimensional Battle Ships

Codeforces Round #Pi (Div. 2) は寝坊して不参加です。代わりに virtual participation やったら 4 完でした。

解法

二分探索で解きました。

med個目までshotした時嘘を付いているとはっきりわかるならtrueを,そうでないならfalseを返す関数を作ります。これがO(n \log n)程度でできるようにしたいです。

まず入力xをmed個目まででソートします。

Aliceが嘘をついていない可能性がある場合は1とx[0]の間,x[i]とx[i+1]の間,x[med-1]とnの間に少なくともk個の船が入っているはずです。これを計算して判定しましょう。

const int MAXM = 200200;
int x[MAXM];
int n, k, a;

bool ok(int med) {
    vector<int> q(med);
    for (int i = 0; i < med; i++) q[i] = x[i];
    sort(q.begin(), q.end());
    int cnt = 0;
    {
        int cur = 0;
        while (cur < q[0]) {
            cur += a;
            if (cur < q[0]) cnt++;
            cur += 1;
        }
    }
    for (int i = 0; i < med-1; i++) {
        int cur = q[i];
        while (cur < q[i+1]) {
            cur += a;
            if (cur < q[i+1]) cnt++;
            cur += 1;
        }
    }
    {
        int cur = q[med-1];
        while (cur <= n) {
            cur += a;
            if (cur <= n) cnt++;
            cur += 1;
        }
    }
    return cnt < k;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n >> k >> a;
    int m;
    cin >> m;
    for (int i = 0; i < m; i++) {
        cin >> x[i];
    }
    int low = 0, high = m;
    while (high - low > 1) {
        int med = (high + low) / 2;
        if (ok(med)) high = med;
        else low = med;
    }
    if (high == m && !ok(high)) cout << -1 << endl;
    else cout << high << endl;
    return 0;
}