Typical DP Contest F 準急

方針

i番目の駅に止まり、i+1番目に止まらないような電車の止まり方の場合の数をdp[i]とする。
これを更新したいのだけれど、愚直にやるとO(nk)になってしまってダメ。



なので、dp[i] + dp[i-1] + dp[i-2] + … + dp[i-k+1]の部分和をsum[i]として、
これも同時に更新しながらDPする。


dp[i] = sum[i-1] + sum[i-2] + … + sum[i-k]であるため、
両端の新たに増える部分と減る部分だけを操作すればいい。
すると全体でO(n)で出来る。

ソースコード

const int mod = (int)1e9+7, MX = 1000100;
int n, k, dp[MX], sum2, sum[MX];


int main(){
	cin >> n >> k;
	
	dp[1] = sum[1] = 1;
	
	for(int i = 2; i <= n; i++){
		dp[i] = sum2 + (i < k);
		
		(sum2 += sum[i-1]) %= mod;
		if(i >= k) (sum2 += mod - sum[i-k]) %= mod;
		sum[i] = (sum[i-1] + dp[i]) % mod;
	}
	cout << dp[n] << endl;
	
	return 0;
}