Typical DP Contest F: 準急 (動的計画法)

解法

(駅i+1で連続j+1回目の停車をする組み合わせ)
 = (駅iで連続j回目の停車をする組み合わせ)

なので、愚直にやってもO(NK)で解ける。工夫して、

(駅i+1で停車する組み合わせ)
 = (駅iで停車する組み合わせ) + (駅iで通過する組み合わせ)
 - (駅i+1-Kで通過する組み合わせ)

とするとO(N)で解けるようになる。

コード

import java.io.IOException;

public class Main {

	private static final int MOD = 1000000007;

	public static void main(String[] arg) {
		int N = nextInt();
		int K = nextInt();

		// dp[i][0]:=駅iを通過する組み合わせの数
		// dp[i][1]:=駅iで止まる組み合わせの数
		long[][] dp = new long[N + 1][2];
		dp[0][0] = 1;
		dp[1][1] = 1;

		for (int n = 1; n < N; n++) {
			dp[n + 1][1] += dp[n][0] + dp[n][1];
			if (n + 1 - K >= 0) {
				dp[n + 1][1] -= dp[n + 1 - K][0];
			}
			dp[n + 1][1] += MOD * 2;
			dp[n + 1][1] %= MOD;

			dp[n + 1][0] += dp[n][0] + dp[n][1];
			dp[n + 1][0] %= MOD;
		}

		System.out.println(dp[N][1]);

	}

	static int nextInt() {
		int c;
		try {
			c = System.in.read();
			while (c != '-' && (c < '0' || c > '9'))
				c = System.in.read();
			if (c == '-')
				return -nextInt();
			int res = 0;
			while (c >= '0' && c <= '9') {
				res = res * 10 + c - '0';
				c = System.in.read();
			}
			return res;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return -1;
	}

}