[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); }
来源:https://www.cnblogs.com/birchtree/p/11241982.html