[CF 712D] Memory and Scores

14 篇文章 0 订阅
12 篇文章 0 订阅

###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} (1xxkxk+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} (xkxk+1)2t(1x1)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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值