[Codeforces712D] Memory and Scores(DP+前缀和优化)(不用单调队列)
题面
两个人玩游戏,共进行t轮,每人每轮从[-k,k]中选出一个数字,将其加到自己的总分中。已知两人的初始得分分别为a和b,求第一个人最后获胜的方案数。两种方案被认为是不同的,当且仅当存在其中一轮,其中一人选到的数字不同。a, b, t≤100,k≤1000
分析
两个人的操作是独立的,设\(dp1[i][j]\)表示第1个人玩i轮得到j分的方案数,第2个人同理
则有\(dp1[0][a]=0\)
\(dp1[i][j]=\sum _{u=j-k}^{j+k} dp1[i-1][u]\)
第2个人只需要把dp的初始值改成\(dp2[0][b]=0\)即可。这样的空间复杂度是\(O(kt^2)\),时间复杂度是\(O(k^2t^2)\),考虑优化。
首先可以用滚动数组,这样空间复杂度就变成了\(O(kt)\)
注意到\(u \in [j-k,j+k]\),可以用前缀和优化,定义\(sum1[i][j] = \sum_{u=-maxv}^{maxv} sum1[i][u]\),则dp方程可以改写成\(dp1[i][j]=sum[i-1][j+k]-sum[i-1][j+k-1]\).时间复杂度\(O(kt^2)\),对于dp2我们同理维护
最后统计答案的时候只需要用第1个人得到i分的方案数乘上第2个人得到<i分的方案数即可,这时候又可以用上我们的sum数组
\[ans=\sum_{i=-maxv}^{maxv} dp1[t][i] \times sum2[t][i-1]\]
代码
#include<iostream>
#include<cstdio>
#define maxv 200100
#define mod 1000000007
using namespace std;
int a,b,k,t;
struct arr{
long long a[maxv*4+5];
inline long long& operator [] (const int index){
return a[index+maxv*2];
}
};
arr dp1[2],dp2[2];
arr sum1[2],sum2[2];
int main(){
int now1,now2;
scanf("%d %d %d %d",&a,&b,&k,&t);
dp1[0][a]=1;
for(int j=-maxv;j<=maxv;j++) sum1[0][j]=(sum1[0][j-1]+dp1[0][j])%mod;
now1=0;
for(int i=1;i<=t;i++){
now1^=1;
for(int j=-maxv;j<=maxv;j++){
dp1[now1][j]=sum1[now1^1][j+k]-sum1[now1^1][j-k-1];
dp1[now1][j]=(dp1[now1][j]+mod)%mod;
}
sum1[now1][-maxv-1]=0;
for(int j=-maxv;j<=maxv;j++){
sum1[now1][j]=sum1[now1][j-1]+dp1[now1][j];
sum1[now1][j]%=mod;
}
}
dp2[0][b]=1;
for(int j=-maxv;j<=maxv;j++) sum2[0][j]=(sum2[0][j-1]+dp2[0][j])%mod;
now2=0;
for(int i=1;i<=t;i++){
now2^=1;
for(int j=-maxv;j<=maxv;j++){
dp2[now2][j]=sum2[now2^1][j+k]-sum2[now2^1][j-k-1];
dp2[now2][j]=(dp2[now2][j]+mod)%mod;
}
sum2[now2][-maxv-1]=0;
for(int j=-maxv;j<=maxv;j++){
sum2[now2][j]=sum2[now2][j-1]+dp2[now2][j];
sum2[now2][j]%=mod;
}
}
long long ans=0;
for(int i=-k*t+a;i<=k*t+a;i++){
ans+=dp1[now1][i]*sum2[now2][i-1]%mod;
ans%=mod;
}
printf("%I64d\n",ans);
}