読者です 読者をやめる 読者になる 読者になる

土下座しながら探索中

主に競技プログラミング

Typical DP Contest F : 準急

典型DPコンテスト 動的計画法

問題リンク:

F: 準急 - Typical DP Contest | AtCoder

解法:
dp[i] := i番目の駅に停まらない数 = dp[max(0,i-K)] + ... + dp[i-1]
初期値は dp[0] = 1, dp[1] = 0
また、dp[N] = 0
dp[1]=dp[N]=0は、必ずその駅にとまることを意味する
dp[i]は
max(0,i-K)駅では停車せず、開区間(max(0,i-K),i)の各駅で停車する総数と
....
(i-2)駅では停車せず、(i-1)駅で停車する総数と
閉区間[max(0,i-K),i]のどの駅にも停車しない総数の和として表される
愚直に数えると間に合わないのでdpの総和を持っておく

コード:

#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)

using namespace std;

typedef long long ll;
const ll mod = 1000000007LL;
const int MAX = 1000010;
ll dp[MAX];
int N,K;

int main() {
dp[0] = 1;
dp[1] = 0;
cin >> N >> K;
/*-- debug
REP(i,2,N+2) {
if( i == N ) { dp[i] = 0; continue; }
for(int j=max(0,i-K);j<i;j++) {
( dp[i] += dp[j] ) %= mod;
}
}
cout << dp[N+1] << endl;
debug -- */

ll sum = 1;
REP(i,2,N+2) {
if( i == N ) {
dp[i] = 0;
} else {
dp[i] = sum;
( sum += dp[i] ) %= mod;
}
if( i - K >= 0 ) { sum -= dp[i-K]; while( sum < 0LL ) sum += mod; }
}
cout << dp[N+1] << endl;
return 0;
}