[Codeforces712D] Memory and Scores(DP+前缀和优化)(不用单调队列)

[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);
}

猜你喜欢

转载自www.cnblogs.com/birchtree/p/11241982.html
今日推荐