はまやんはまやんはまやん

hamayanhamayan's blog

storage [OyamaC]

https://www.hackerrank.com/contests/oyamac/challenges/storage

前提知識

解説

https://www.hackerrank.com/contests/oyamac/challenges/storage/submissions/code/1321979183

見た目、ナップサック問題に近いし、yes/no系動的計画法でよく見る形でもあるので、
yes/no系動的計画法で解くことを考えてみよう。

以下のようなDPが思いつく。

dp[i][k][w] := i個目までの荷物を使って、k個の荷物を選択したときに、容量wが達成できるか
dp[i][k][w] = dp[i - 1][k][w] | dp[i - 1][k - 1][w - W[i]]

DPのサイズは103103103なので、かなりギリギリ。
だが、この遷移はbitset高速化ができる形になっている。

最後のwをbitsetのbitで表現することにすると、更新式は以下のように変わる。
dp[i][k] = dp[i - 1][k] | (dp[i - 1][k - 1] << W[i])
これで/64するので間に合うようになる。

int A, N, K, W[1010];
bitset<1010> dp[2][1010];
//---------------------------------------------------------------------------------------------------
void _main() {
    cin >> A >> N >> K;
    rep(i, 0, N) cin >> W[i];

    dp[0][0].set(0);
    rep(i, 0, N) {
        int cu = i % 2;
        int ne = 1 - cu;
        rep(k, 0, K + 1) dp[ne][k].reset();

        rep(k, 0, K + 1) {
            dp[ne][k] |= dp[cu][k];
            dp[ne][k + 1] |= dp[cu][k] << W[i];
        }
    }

    rep(k, 0, K + 1) if (dp[N % 2][k][A]) {
        cout << "YES" << endl;
        return;
    }
    cout << "NO" << endl;
}