###Description
有两个人在玩游戏,第一个人初始有a分,第二个人有b分。
总共玩t轮游戏,每一轮游戏每个人可以从[-k,k]中任选一个数,加进自己的分数中。
分数大的人获胜。
求有多少种情况先手获胜。
答案mod 1e9+7
1 ≤ a, b ≤ 100, 1 ≤ k ≤ 1000, 1 ≤ t ≤ 100
###Solution
直觉告诉我这道题应该是有数学方法的,然而本蒟蒻不会。。。
那么就来Dp吧~
首先,每一轮游戏可以拆成两轮一样的游戏。
那么我们就相当于玩2t轮,每一轮两个人的分数差值会最大+k,最小-k
设Fi,j表示第i轮,两个人的分差为j的方案数。
那么Fi,j可以对Fi+1,j-k~Fi+1,j+k贡献。
如何快速地处理区间加?
差分然后前缀和呗~
2018.10.30 UPD:
本来还想留着出题的。。。
显然答案的生成函数是
(
∑
i
=
−
k
k
x
i
)
2
t
(\sum_{i=-k}^{k}x^i)^{2t}
(∑i=−kkxi)2t
也就是
(
x
−
k
−
x
k
+
1
1
−
x
)
2
t
({x^{-k}-x^{k+1}\over 1-x})^{2t}
(1−xx−k−xk+1)2t
(
x
−
k
−
x
k
+
1
)
2
t
(
1
1
−
x
)
2
t
(x^{-k}-x^{k+1})^{2t}({1\over 1-x})^{2t}
(x−k−xk+1)2t(1−x1)2t
前面那一项展开来只有2t项,每一项都是组合数,后面的也是组合数
直接枚举前面的每一项计算,预处理一个组合数的前缀和即可
当然也能用容斥推
###Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 400005
using namespace std;
const int mo=1e9+7;
int a,b,k,t,p,q,ans,f[2][N];
int main() {
scanf("%d%d%d%d",&a,&b,&k,&t);
int l=a-b-2*k*t,r=a-b+2*k*t;
f[0][a-b-l]=1;p=0;q=1;
fo(i,0,2*t-1) {
memset(f[q],0,sizeof(f[q]));
fo(j,l,r) if (f[p][j-l]) (f[q][j-l-k]+=f[p][j-l])%=mo,
(f[q][j-l+k+1]+=mo-f[p][j-l])%=mo;
fo(j,1,r-l+1) (f[q][j]+=f[q][j-1])%=mo;
p=q;q=1-p;
}
fo(i,1,r) (ans+=f[p][i-l])%=mo;
printf("%d",ans);
}