博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Memory and Scores
阅读量:7011 次
发布时间:2019-06-27

本文共 3267 字,大约阅读时间需要 10 分钟。

Memory and Scores

题目链接:

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),代码如下:

1 #include
2 #include
3 #define M 1000000007LL 4 #define TIME 105 5 #define DIFF 300000 6 #define BASE 150000 7 using namespace std; 8 typedef long long LL; 9 LL a,b,k,t,ans;10 LL dp[TIME][DIFF];11 int main(void){12 cin>>a>>b>>k>>t;13 dp[0][a-b+BASE]=1;14 LL upper=a-b+BASE+2*k*t;15 LL lower=a-b+BASE-2*k*t;16 for(LL times=1;times<=t;++times){17 for(LL diff=lower;diff<=upper;diff++){18 for(LL m=0;m<=2*k;m++){19 LL add=-2*k+m;20 if(diff+add>=lower){21 if(add)dp[times][diff]+=(dp[times-1][diff+add]+dp[times-1][diff-add])*(m+1);22 else dp[times][diff]+=dp[times-1][diff]*(m+1);23 dp[times][diff]%=M;24 }25 }26 }27 }28 for(int i=BASE+1;i<=upper;++i)29 ans=(ans+dp[t][i])%M;30 cout<
<
View Code

很显然,这会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),代码如下:

1 #include
2 #include
3 #define M 1000000007LL 4 #define TIME 105 5 #define DIFF 500000 6 #define BASE 250000 7 using namespace std; 8 typedef long long LL; 9 LL a,b,k,t,ans;10 LL dp[TIME][DIFF];11 LL pre[DIFF];12 int main(void){13 cin>>a>>b>>k>>t;14 dp[0][a-b+BASE]=1;15 LL upper=a-b+BASE+2*k*t;16 LL lower=a-b+BASE-2*k*t;17 for(LL times=1;times<=t;++times){18 for(LL diff=lower;diff<=upper;diff++)19 pre[diff]=pre[diff-1]+dp[times-1][diff],pre[diff]%=M;20 for(LL m=0;m<=2*k;m++){21 LL add=-2*k+m;22 if(add)dp[times][lower]23 +=(dp[times-1][lower+add]+dp[times-1][lower-add])*(m+1);24 else dp[times][lower]+=dp[times-1][lower]*(m+1);25 dp[times][lower]%=M;26 }27 for(LL diff=lower+1;diff<=upper;diff++){28 dp[times][diff]=dp[times][diff-1]29 +(pre[min(upper,diff+2*k)]-pre[diff-1])30 -(pre[diff-1]-pre[max(lower,diff-1-2*k)-1]);31 dp[times][diff]=(dp[times][diff]+M)%M;32 //记得+M,减法模运算可能会出现负数33 }34 }35 for(int i=BASE+1;i<=upper;++i)36 ans=(ans+dp[t][i])%M;37 cout<
<

 

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

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

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

 

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

 

转载于:https://www.cnblogs.com/barrier/p/5875456.html

你可能感兴趣的文章
ZooKeeper 使用 Java API
查看>>
Hexo 搭建个人博客 #05 利用 Travis CI 帮你自动部署
查看>>
使用vue-cli3创建项目,踩坑记录
查看>>
Java----IDEA+SpringBoot+MyBatis初步学习心得
查看>>
简单实现js关键字new
查看>>
android高级ui之ListView源码分析
查看>>
我们”黑客增长失败了“,剖析裂变失败的5个原因
查看>>
前端技术人员的发展之路
查看>>
新手收入学习算法?算法如何入门以及零基础入门算法应该学些什么?学习路线是什么...
查看>>
jq滚动条问题
查看>>
入门教程 | 5分钟从零构建第一个 Flink 应用
查看>>
使用JUnit进行单元测试
查看>>
golang 更友好的格式化输出
查看>>
spring Core Technologies The IoC container
查看>>
空间站R2机器人“复苏”:可执行危险任务
查看>>
JavaScript 立即执行函数、逗号运算
查看>>
Python生物学Cookbook - Bioinformatics with Python Cookbook 2nd -2018.pdf
查看>>
十年经验架构金三银四BAT跳槽面试感悟!
查看>>
android代码dialog优化实例
查看>>
Docker 第一课 - 构建你的容器
查看>>