1. 程式人生 > >Codeforces 712D DP

Codeforces 712D DP

can 人的 [1] clu name spa 數字 思路 大於

題意:有2個人玩遊戲,他們都有個初始值a和b, 遊戲進行t輪, 每次可以選擇加上一個[-k, +k]之間的數字,問有多少種方案a的和嚴格大於b的和。

思路:如果不考慮多於這個條件,只是詢問有多少種方案的化,這是一個數塔模型的DP, 設dp[i][j]為到i位置,前面的數的和為j的方案數,直接轉移即可。需要用前綴和優化。對兩個人分別DP一次,然後枚舉第一個人的最後的和,去找第二個人有多少個和小於它的方案。這個也需要用前綴和來優化。

代碼:

#include <bits/stdc++.h>
#define LL long long 
using namespace std;
const LL mod = 1000000007;
const int maxn = 210010;
LL dp[2][110][maxn];
LL sum[2][maxn];
LL get_sum(int pos, int l, int r, int lb, int rb) {
	l = max(l, lb);
	r = min(r, rb);
	if(l > r) return 0;
	return (sum[pos][r] - sum[pos][l - 1] + mod) % mod;
}
int main() {
	int a, b, k, t;
	scanf("%d%d%d%d", &a, &b, &k, &t);
	int ed = 210000;
	dp[0][0][t * k + 1 + a] = 1;
	dp[1][0][t * k + 1 + b] = 1;
	for (int pos = 0; pos <= 1; pos++) {
		for (int i = 1; i <= t; i++) {
			for (int j = 1; j <= ed; j++) 
				sum[pos][j] = (sum[pos][j - 1] + dp[pos][i - 1][j]) % mod;
			for (int j = 1; j <= ed; j++)
				dp[pos][i][j] = get_sum(pos, j - k, j + k, 1, ed);
		}
	}
	for (int pos = 0; pos <= 1; pos++) {
		for (int i = 1; i <= ed; i++)
			sum[pos][i] = (sum[pos][i - 1] + dp[pos][t][i]) % mod;
	}
	LL ans = 0;
	for (int i = a + 1; i <= a + 1 + 2 * t * k; i++) {
		ans = (ans + (dp[0][t][i] * get_sum(1, 1, i - 1, b + 1, b + 1 + 2 * t * k)) % mod) % mod;
	}
	printf("%lld\n", ans);
} 

  

Codeforces 712D DP