组合计数 ---- Codeforces Round #370 (Div. 2)D. Memory and Scores[dp]

题目大意:Memory 和 Lexa分别取数,取 t t t轮,每一轮取的数字的范围为 [ − k , k ] [−k,k] [k,k],并且将取的数字加他们的得分,问有多少种方案Memory的得分严格大于Lexa。Memory和Lexa分别的初始分数为 a , b a,b a,b


解题思路
我 们 设 f [ i ] [ j ] 为 从 第 i 轮 抽 数 之 后 这 些 数 之 和 为 j 的 方 案 数 . 我们设f[i][j]为从第i轮抽数之后这些数之和为j的方案数. f[i][j]ij.
那 么 f [ i ] [ j ] = ∑ k = j − k j + k f [ i − 1 ] [ k ] 那么f[i][j]=\sum_{k=j-k}^{j+k}f[i-1][k] f[i][j]=k=jkj+kf[i1][k]
因 为 取 值 范 围 是 [ − k , k ] 中 间 可 能 会 出 现 负 数 因为取值范围是[-k,k]中间可能会出现负数 [k,k]
那 么 我 们 就 将 区 间 迁 移 以 一 下 [ 0 , 2 k ] 那么我们就将区间迁移以一下[0,2k] [0,2k]
我 们 还 可 以 优 化 一 下 因 为 对 于 f [ i ] 的 每 一 个 j 都 只 是 用 了 上 一 层 f [ i − 1 ] 的 数 值 我们还可以优化一下因为对于f[i]的每一个j都只是用了上一层f[i-1]的数值 f[i]jf[i1]
那 么 我 们 就 可 以 预 处 理 出 上 一 层 的 前 缀 和 s u m [ j ] 那么我们就可以预处理出上一层的前缀和sum[j] sum[j]


但 我 们 得 到 f [ i ] [ j ] 之 后 我 们 就 可 以 枚 举 M e m o r y 的 最 后 的 加 上 的 数 值 为 x 但我们得到f[i][j]之后我们就可以枚举Memory的最后的加上的数值为x f[i][j]Memoryx
那 么 L e x a 的 加 上 的 分 数 就 是 ∈ [ 0 , x − ( b − a ) − 1 ] 那么Lexa的加上的分数就是\in[0,x-(b-a)-1] Lexa[0,x(ba)1]
同 理 我 们 也 可 以 预 处 理 前 缀 s u m ∈ [ 0 , x − ( b − a ) − 1 ] ; 同理我们也可以预处理前缀sum\in[0,x-(b-a)-1]; sum[0,x(ba)1];


下 面 看 代 码 下面看代码


#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1) 
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define rep_(i,a,b) for( int i = (a); i >= (b); -- i)
#define for_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 2e5+1010, mod = 1e9 + 7;
const double eps = 1e-10;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) 
{
    read(first);
    read(args...);
}
int a, b, K, T;
ll dp[110][N];//表示第i论得分为j的方案数
ll sum[N];
int main()
{
    read(a,b,K,T);
    dp[0][0] = 1;
    _rep(i,1,T)
    {
         _rep(j,0,2*K*T+100)//细节这里注意范围因为a-b可能会是-99
           sum[j] = ((j ? sum[j - 1] : 0) + dp[i-1][j])%mod;
       
        _rep(j,0,2*K*T+100)
            dp[i][j] = (sum[j] - (j - 2 * K - 1 >= 0 ? sum[j - 2 * K - 1] : 0) + mod) % mod;
    }
    int EPS = b - a;
    ll ans = 0;
    _rep(i,0,2*K*T+100)
    sum[i] = ((i ? sum[i - 1] : 0) + dp[T][i]) % mod;
    _rep(i,EPS+1,2*K*T)
    {
         ll res = 0;
         res = sum[i-EPS-1] % mod;
         ans = (ans + res * dp[T][i] % mod) % mod;
    }
    cout << ans << endl;
    return 0;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值