Official

E - Simultaneous Kagamimochi Editorial by MMNMM


\(K\) 個 \((0\leq K\leq\dfrac N2)\) の鏡餅を作るとき、先頭 \(K\) 個と末尾 \(K\) 個の餅を使うとしてかまいません(上に乗せられている餅が先頭 \(K\) 個と異なる場合、先頭 \(K\) 個の餅が上になるように入れ替えることができます。末尾 \(K\) 個も同様です)。
また、上に乗せる \(K\) 個の餅と下段として使われる \(K\) 個の餅を決めたとき、それらをすべて使って \(K\) 個の鏡餅が作れることは、それぞれ小さいほうから組にしたときに \(K\) 個の鏡餅が作れることと同値です(\(\Leftarrow\) は明らかです。\(\Rightarrow\) は、出来上がった鏡餅を上の餅の大きさでソートしたときに下の餅がソートされていないなら、下の餅をソートしても \(K\) 個の鏡餅を作れることから言えます)。

以上より、\(K\) を定めたときに \(K\) 個の鏡餅が作れるかを判定することは \(O(K)\) 時間で可能です。

ある非負整数 \(k\) について鏡餅を \(k\) 個作れるなら、任意の非負整数 \(l\ (l\leq k)\) について鏡餅を \(l\) 個作れるので、二分探索を行うことでこの問題を解くことができます。

時間計算量は \(O(N\log N)\) となります。

#include <algorithm>
#include <iostream>
#include <vector>
#include <ranges>

int main() {
    using namespace std;
    unsigned N;
    cin >> N;

    vector<unsigned> A(N);
    for (auto&& a : A)
        cin >> a;

    // 判定関数
    // K 個の鏡餅を作ることができるか?
    const auto check{
        [N, &A](unsigned K) {
            for (unsigned i = 0; i < K; ++i)
                // 先頭と末尾から K 個ずつ取ってきて
                if (A[i] * 2 > A[N - K + i])
                    // どれか 1 つでも半分より大きかったら false
                    return false;
            // そうでなければ true
            return true;
        }
    };

    // 0 から N / 2 の間で、判定関数が true になる最大の値(false になる最小の値 - 1)を二分探索で求める
    cout << *ranges::partition_point(views::iota(0U, N / 2 + 1), check) - 1 << endl;

    return 0;
}

posted:
last update: