Codeforces round 627 Div.3 E
March 16, 2020
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;
}