Codeforces 712D Memory And Scores 前缀和+DP

来源:互联网 发布:linux 下载速度很慢 编辑:程序博客网 时间:2024/06/06 15:52

点击打开链接

Problem D

题意:两人初始分数为(a,b) 总共t轮 每轮 两人随机从[-k,k]中选一个数加到自己的得分上.a,b,t<=100,k<=1000.问t轮后第一个人分数大于第2个人的方法数%mod,任意一轮中抽的不一样视为不同方案.


法1:设dp[i][dif] i轮后 两人相差dif(设个offset转移负数)
dp[i][dif]+=dp[i-1][dif+(x-y)] -2k<=x-y<=2k -> dp[i][dif]+=(2k+1-z)*dp[i-1][dif+z) -2k<=z<=2k 可以向下面的方法一样化简


法2:设dp[i][sum] 抽i次 总和为sum的方法数  
dp[i][sum]+=dp[i-1][sum] x=[-k,k]  时间复杂度为O(t*kt*k) TLE
化解dp[i][sum]=dp[i][sum-1]-dp[i-1][sum+k]+dp[i-1][sum-1-k] (dp[i][sum-1]拆出来多一项少一项)

时间复杂度降为O(t*tk),枚举第二个抽人的sum 则第一个人至少要抽sum+b-a+1,利用前缀求出至少抽sum的方法数即可 

#include <bits/stdc++.h>using namespace std;typedef long long ll;const ll mod=1e9+7;const int N=3e5+20;ll a,b,k,t;ll dp[110][N*2],pre[N*2];ll calc(ll i,ll j){if(j<0)return 0;return dp[i][j];}int main(){while(cin>>a>>b>>k>>t){int offset=N;// offset-> zeromemset(dp,0,sizeof(dp));dp[0][offset+0]=1;for(int i=1;i<=t;i++){for(int j=-offset;j<=offset;j++){//j-k~j+k//j-k-1~j-k-1dp[i][j+offset]=(calc(i,j-1+offset)+calc(i-1,j+k+offset)-calc(i-1,j-k-1+offset))%mod;dp[i][j+offset]=(dp[i][j+offset]%mod+mod)%mod;}}ll ans=0;//pre[i]  for(int i=offset;i>=-offset;i--)pre[i+offset]=(pre[i+1+offset]+dp[t][i+offset])%mod;for(int i=-offset;i<=offset;i++){int o=i+b-a+1;ans=(ans+(dp[t][i+offset]*pre[max(0,o+offset)])%mod)%mod;}cout<<ans<<endl;}return 0;}



 
阅读全文
0 0
原创粉丝点击