<-- home

Codeforces round 627 Div.3 E

https://codeforces.com/contest/1324/problem/E

解いたのでメモ。

以下、法をとして考える。

1~n番目の睡眠それぞれで、を選ぶかを選ぶか決められるので、 選び方の組み合わせは全部で個ある。なので、全探索では制限時間に間に合わない。 そこで、i番目の睡眠をしたとき、番目の睡眠時間の選択でどう選んだかという情報は、「現在時刻」に集約されることに着目して動的計画法で解く。

とすると、jが到達可能な状態か、つまりi番目の睡眠をしたときに時刻jになっていることがありうるかどうかを考慮しないといけない。これだと少しややこしいので、

と定義すると、i番目の睡眠を終えた時点で、現在時刻が、

となることから、

と定義して問題を解く。 状態のとき、その状態の時刻を求めるためには、を求める必要があるが、事前に累積和を求めておくことで、で計算できる。状態からは、を選んでへ遷移する場合と、を選んでへ遷移する場合がある。

実装

全体の計算量は

// テンプレ省略

#define MAX_N 2000
#define MAX_H 2000
i64 N, H, L, R;
i64 A[MAX_N];
i64 dp[MAX_N + 1][MAX_N + 1];

int main() {
    cin >> N >> H >> L >> R;
    REP(i, N) cin >> A[i];

    vector<i64> C(N + 1, 0);
    REP(i, N) {
        C[i + 1] = C[i] + A[i];
        C[i + 1] %= H;
    }

    REP(i, N + 1) {
        REP(j, N + 1) {
            dp[i][j] = 0;
        }
    }

    i64 nt;
    REP(i, N) {
        for (i64 j = 0; j <= i; j++) {
            REP(k, 2) {
                nt = C[i + 1] - ((j + k) % H);
                if (nt < 0) nt += H;
                chmax(dp[i + 1][j + k], dp[i][j] + (L <= nt && nt <= R));
            }
        }
    }

    i64 max_n = 0;
    REP(i, N + 1) {
        chmax(max_n, dp[N][i]);
    }
    cout << max_n << endl;

    return 0;
}