【Codeforces Round 370 (Div 2) D】【前缀和打标记】Memory and Scores 双人随机数值增减K A比B多的方案数

D. Memory and Scores
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Memory and his friend Lexa are competing to get higher score in one popular computer game. Memory starts with score a and Lexa starts with score b. In a single turn, both Memory and Lexa get some integer in the range [ - k;k] (i.e. one integer among - k,  - k + 1,  - k + 2, ...,  - 2,  - 1, 0, 1, 2, ..., k - 1, k) and add them to their current scores. The game has exactly t turns. Memory and Lexa, however, are not good at this game, so they both always get a random integer at their turn.

Memory wonders how many possible games exist such that he ends with a strictly higher score than Lexa. Two games are considered to be different if in at least one turn at least one player gets different score. There are (2k + 1)2t games in total. Since the answer can be very large, you should print it modulo 109 + 7. Please solve this problem for Memory.

Input

The first and only line of input contains the four integers abk, and t (1 ≤ a, b ≤ 1001 ≤ k ≤ 10001 ≤ t ≤ 100) — the amount Memory and Lexa start with, the number k, and the number of turns respectively.

Output

Print the number of possible games satisfying the conditions modulo 1 000 000 007 (109 + 7) in one line.

Examples
input
1 2 2 1
output
6
input
1 1 1 2
output
31
input
2 12 3 1
output
0
Note

In the first sample test, Memory starts with 1 and Lexa starts with 2. If Lexa picks  - 2, Memory can pick 01, or 2 to win. If Lexa picks - 1, Memory can pick 1 or 2 to win. If Lexa picks 0, Memory can pick 2 to win. If Lexa picks 1 or 2, Memory cannot win. Thus, there are3 + 2 + 1 = 6 possible games in which Memory wins.


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int A, B, K, T, KK;
const int BAS = 2e5 + 200;
const int TOP = 4e5 + 200;
int f[105][TOP];
int plu[TOP];
void add(int &x, int y)
{
	if ((x += y) >= Z)x -= Z;
}
int main()
{
	while (~scanf("%d%d%d%d", &A, &B, &K, &T))
	{
		KK = K + K;
		int bot, top;
		MS(f, 0); f[0][bot = top = BAS + A - B] = 1;
		for (int i = 0; i < T; ++i)
		{
			for (int j = bot; j <= top; ++j)
			{
				add(plu[j - KK], f[i][j]);
				add(plu[j + 1], Z - f[i][j]); add(plu[j + 1], Z - f[i][j]);
				add(plu[j + KK + 2], f[i][j]);

				/*
				j-2K处获得一个增幅为f[i][j]
				j-2K处就相应得到增量f[i][j]

				j-(2K-1)处的增幅=j-2K处的增幅
				j-(2K-1)处的增量=j-2K处的增量+j-(2K-1)处的增幅
				
				j+1处获得一个增幅为-2f[i][j]
				j+2K+1处获得一个增幅为f[i][j]
				*/
			}
			bot -= KK;
			top += KK;
			for (int j = bot; j <= top; ++j)
			{
				f[i + 1][j] = f[i + 1][j - 1];
				add(plu[j], plu[j - 1]);
				add(f[i + 1][j], plu[j]);
			}
			MS(plu, 0);
		}
		int ans = 0;
		for (int i = BAS + 1; i <= top; ++i)add(ans, f[T][i]);
		printf("%d\n", ans);
	}
	return 0;
}
/*
【题意】
初始A的得分为A,B的得分为B
游戏持续T(100)轮,
在每轮之中,A和B都可能各自独立地获得[-K,K]的增量,K is of[1,1000]

问你t轮之后,有多少种方案使得final score of A > final score of B

【类型】
DP 高次前缀和

【分析】
我们发现,如果当前A-B的分数为x,对应的方案数为f[x]
那么这次经过A、B取数之后,其向——
x-2K x-(2K-1) x-(2K-2) ... x ... x+(2K-2) x+(2K-1) x+2K的f[x]的贡献倍数分别是
1       2        3         0         3       2      1
也就是呈等差数列的变化形式。

f[]的大小最大为T*2K*2,是4e5级别
我们暴力转移的复杂度是4e5 * 4K

于是这里要考虑打标记
f[]如果是速度的话,打标记的plu就相当于给定一个变化量的加速度
不仅f[]是以前缀和的形式求得,这里的plu也是以前缀和的形式给出

于是我们要在plu[x-2K] += f[x]
在plu[x+1] -= 2f[x]
在plus[x+2K+2] +=f[x]

然后扫一遍就可以AC啦。

【时间复杂度&&优化】
O(T * T * 4K)

*/


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值