Memory and Scores

题目链接:http://codeforces.com/contest/712/problem/D

dp

因为每轮Memory和Lexa能取的都在[-k,k],也就是说每轮两人分数的变化量在[-2k,2k];

故可以定义状态:dp[times][diff]为第times次Memory和Lexa的分数差为diff的方案数.

而dp[times][diff]可以从dp[times-1][diff-2k]到dp[times-1][diff+2k]转移而来;

又因为变化量为-2k时的方案数为1(-k,k),

变化量为-2k+1时的方案数为2(-k,k-1;-k+1,k),

变化量为-2k+2时的方案数为3(-k,k-2;-k+1,k-1;-k+2,k),

...,

变化量为-2k+m时的方案数为m+1,

...,

变化量为0时的方案数为2k+1,

...,

变化量为2k-m时的方案数为m+1,

...,

变化量为2k-1时的方案数为2,

变化量为2k时的方案数为1.

所以状态转移方程为:dp[times][diff]=dp[times-1][diff-2k]+2*dp[times-1][diff-2k+1]+3*dp[times-1][diff-2k+2]+...+(m+1)*dp[times-1][diff-2k+m]+...+2*dp[times-1][diff+2k-1]+dp[times-1][diff+2k];

这样的话,时间复杂度为O(k2t2),代码如下:

 #include<iostream>
#include<cmath>
#define M 1000000007LL
#define TIME 105
#define DIFF 300000
#define BASE 150000
using namespace std;
typedef long long LL;
LL a,b,k,t,ans;
LL dp[TIME][DIFF];
int main(void){
cin>>a>>b>>k>>t;
dp[][a-b+BASE]=;
LL upper=a-b+BASE+*k*t;
LL lower=a-b+BASE-*k*t;
for(LL times=;times<=t;++times){
for(LL diff=lower;diff<=upper;diff++){
for(LL m=;m<=*k;m++){
LL add=-*k+m;
if(diff+add>=lower){
if(add)dp[times][diff]+=(dp[times-][diff+add]+dp[times-][diff-add])*(m+);
else dp[times][diff]+=dp[times-][diff]*(m+);
dp[times][diff]%=M;
}
}
}
}
for(int i=BASE+;i<=upper;++i)
ans=(ans+dp[t][i])%M;
cout<<ans<<endl;
}

很显然,这会T,所以必须做出优化。

注意到:

dp[times][diff]是在dp[times][diff-1]的基础上前半段各个项减一,后半段各个项加一得到的,所以可以维护一个前缀和数组pre[i],那么

dp[times][diff]=dp[times][diff-1]+(pre[diff+2k]-pre[diff-1])-(pre[diff-1]-pre[(diff-1)-2k-1])

可以在O(1)的时间内完成,优化后的代码时间复杂度为O(kt2),代码如下:

 #include<iostream>
#include<cmath>
#define M 1000000007LL
#define TIME 105
#define DIFF 500000
#define BASE 250000
using namespace std;
typedef long long LL;
LL a,b,k,t,ans;
LL dp[TIME][DIFF];
LL pre[DIFF];
int main(void){
cin>>a>>b>>k>>t;
dp[][a-b+BASE]=;
LL upper=a-b+BASE+*k*t;
LL lower=a-b+BASE-*k*t;
for(LL times=;times<=t;++times){
for(LL diff=lower;diff<=upper;diff++)
pre[diff]=pre[diff-]+dp[times-][diff],pre[diff]%=M;
for(LL m=;m<=*k;m++){
LL add=-*k+m;
if(add)dp[times][lower]
+=(dp[times-][lower+add]+dp[times-][lower-add])*(m+);
else dp[times][lower]+=dp[times-][lower]*(m+);
dp[times][lower]%=M;
}
for(LL diff=lower+;diff<=upper;diff++){
dp[times][diff]=dp[times][diff-]
+(pre[min(upper,diff+*k)]-pre[diff-])
-(pre[diff-]-pre[max(lower,diff--*k)-]);
dp[times][diff]=(dp[times][diff]+M)%M;
//记得+M,减法模运算可能会出现负数
}
}
for(int i=BASE+;i<=upper;++i)
ans=(ans+dp[t][i])%M;
cout<<ans<<endl;
}

这样的代码仍然可以优化:

1.可以用滚动数组来优化空间复杂度,从O(kt2)降低到O(kt),太懒没写╮(╯▽╰)╭;

2.可以用快速傅里叶变换FFT优化时间复杂度,从O(kt2)继续降到O(kt lg(kt)),没学还不会写╮(╯▽╰)╭

//昨天去面试微软俱乐部被嘲讽=。= 定个目标吧,这学期div2稳定4题怎么样?

Memory and Scores的更多相关文章

  1. Codeforces Round #370 (Div. 2) D. Memory and Scores DP

    D. Memory and Scores   Memory and his friend Lexa are competing to get higher score in one popular c ...

  2. Codeforces Round #370 (Div. 2) D. Memory and Scores 动态规划

    D. Memory and Scores 题目连接: http://codeforces.com/contest/712/problem/D Description Memory and his fr ...

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

    [Codeforces712D] Memory and Scores(DP+前缀和优化)(不用单调队列) 题面 两个人玩游戏,共进行t轮,每人每轮从[-k,k]中选出一个数字,将其加到自己的总分中.已 ...

  4. 【26.87%】【codeforces 712D】Memory and Scores

    time limit per test2 seconds memory limit per test512 megabytes inputstandard input outputstandard o ...

  5. [CodeForces - 712D]Memory and Scores (DP 或者 生成函数)

    题目大意: 两个人玩取数游戏,第一个人分数一开始是a,第二个分数一开始是b,接下来t轮,每轮两人都选择一个[-k,k]范围内的整数,加到自己的分数里,求有多少种情况使得t轮结束后a的分数比b高.  ( ...

  6. Codeforces 712 D. Memory and Scores (DP+滚动数组+前缀和优化)

    题目链接:http://codeforces.com/contest/712/problem/D A初始有一个分数a,B初始有一个分数b,有t轮比赛,每次比赛都可以取[-k, k]之间的数,问你最后A ...

  7. CodeForces 712D Memory and Scores

    $dp$,前缀和. 记$dp[i][j]$表示$i$轮结束之后,两人差值为$j$的方案数. 转移很容易想到,但是转移的复杂度是$O(2*k)$的,需要优化,观察一下可以发现可以用过前缀和来优化. 我把 ...

  8. CF370 D Memory and Scores

    dp题 并运用了前缀和 我看题目提示中有fft 我想了下感觉复杂度不过关还是未解 #include<bits/stdc++.h> using namespace std; typedef ...

  9. CF712D Memory and Scores

    题目分析 实际上两个人轮流取十分鸡肋,可以看作一个人取2t次. 考虑生成函数. 为了方便,我们对取的数向右偏移k位. 取2t次的生成函数为: \[ F(x)=(\sum_{i=0}^{2k}x_i)^ ...

随机推荐

  1. C语言之数组

    数组 数组就是在内存空间中,开辟一个大的空间,然后再将这个大的空间均的分为若干份的小空间,每个小空间用来保存一个数据. 1). 数组的专业术语: 长度:指的能存放数据的个数 下标/索引:每一个数据所在 ...

  2. ETL的经验总结

    ETL的考虑        做数据仓库系统,ETL是关键的一环.说大了,ETL是数据整合解决方案,说小了,就是倒数据的工具.回忆一下工作这么些年来,处理数据迁移.转换的工作倒还真的不少.但是那些工作基 ...

  3. Java的常用包

    java.lang:  这个包下包含了Java语言的核心类,如String.Math.Sytem和Thread类等,使用这个包无需使用import语句导入,系统会自动导入这个包中的所有类. java. ...

  4. 选择Blobs (Evision)

    C++ // Sort by decreasing area Blobs.SortObjectsUsingFeature(OBJ_AREA, OBJ_SORT_DESCENDING); // Enum ...

  5. unity 内置的CG结构解析

    一.Cg顶点程序必须在结构中传递顶点数据.几种常用的顶点结构定义在文件UnityCG.cginc中.在大部分情况下仅仅使用它们就够了.结构如下: 1.appdata_base: 包含顶点位置,法线和一 ...

  6. 怎样在linux或者Unix上检查端口是否在使用

     英文原文链接:https://www.cyberciti.biz/faq/unix-linux-check-if-port-is-in-use-command/ Question 1: 怎样在lin ...

  7. attr 和 prop 区别

    jquery 中 attr 和 prop 都表示 "属性",同样是属性为啥还要弄两个! attr 适用于自定义属性 如 定义一个懒加载用的src 栗子 <img class= ...

  8. web 服务器

    作为一个跨专业转行的我来说,对后台一团浆糊,最近在看php,学的进度比较慢 (1)ApacheApache是世界使用排名第一的Web服务器软件.它可以运行在几乎所有广泛使用的计算机平台上.Apache ...

  9. FZU 2240 Daxia & Suneast's problem

    博弈,$SG$函数,规律,线段树. 这个问题套路很明显,先找求出$SG$函数值是多少,然后异或起来,如果是$0$就后手赢,否则先手赢.修改操作和区间查询的话可以用线段树维护一下区间异或和. 数据那么大 ...

  10. java实现线性表

    /** * 线性表 * @author zyyt * */ public  class LinkList {//框架级别的大师级 private int size;//链表的实际大小 private ...