链接:https://ac.nowcoder.com/acm/problem/14553
来源:牛客网

题目描述

小明很喜欢打游戏,现在已知一个新英雄即将推出,他同样拥有四个技能,其中三个小技能的释放时间和固定的伤害值为:

1.乌鸦坐飞机 释放时间:x 固定伤害值:a

2.蜘蛛吃耳屎 释放时间:y 固定伤害值:b

3.饿狼前进  释放时间:z 固定伤害值:c

他还有一个大招,其释放的时间是一个区间【L,R】,可以在区间内任意时间点释放出技能,其如果在L+i时刻释放技能,其能够打出的伤害值为:temp+A*i

这里temp值表示技能的基础伤害(同时也就是在时刻L释放技能的伤害值),A是一个常数。

小明很喜欢研究连招使得在有限的时间内打出最高的伤害,现在他想要在T长度单位时间内打出最高的伤害,问这个最大伤害值。

输入描述:

  1. 本题包含多组数据。
    输入格式为:
    T
    x a
    y b
    z c
    L R temp A
    数据范围:
    1<=T<=1e5
    1<=x,y,z,L,R<=T
    L<=R
    <=a,b,c,temp,A<=1e5
    输出描述:
  1. 输出包含一行,输出能够打出的最高伤害值。
示例1
输入
  1. 8
  2. 3 1
  3. 2 3
  4. 1 3
  5. 3 3 3 3
    输出
  1. 24
    备注:
  1. 大招:蓄力时间最短L秒,最多R秒。无限次释放,释放之后照成的伤害是随着时间增加的
    蓄力L秒释放能够造成Temp的伤害
    蓄力L+1秒释放能够造成Temp+1*A的伤害
    依次类推

题意:小明有三个小技能和一个大招,每个小技能消耗ai的时间,打出bi的伤害,大招的基础伤害为temp,基础时间为L,大招可以蓄力,得到的伤害为temp+(T-L)*A,其中T为大招的时间,上限为R,求总时间为t打出的最高伤害
题解:对于三个小技能可以直接使用普通的背包dp,而对于大招,如果暴力地把大招时间拆成L,L+1....R,那么复杂度将是O(N^2),很明显会超时,而观察到对大招来说dp[i]=max(dp[j]+temp+A*(i-L-j)),所以对于j>k, 如果 j 相对于k更优,那么(dp[j]+temp+A*(i-L-j)) - (dp[k]+temp+A*(i-L-k)) > 0,所以有dp[j]-dp[k]>A*(j-k),可以使用斜率优化dp,而由于这里的A为常数,和 i 无关,所以可以直接知道当前点是否最优,不需要维护凸包,也就是可以不使用斜率优化dp,而使用单调队列优化dp(斜率优化dp和单调队列优化dp区别就在插入新点时前者是维护凸包后者是维护单调队列)

斜率优化dp

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<vector>
  6. #include<queue>
  7. #include<map>
  8. using namespace std;
  9. //#define io_test
  10. #define debug(x) cout<<x<<"####"<<dp[x][0]<<"##"<<dp[x][1]<<endl;
  11. typedef long long ll;
  12. ll dp[],pq[];
  13. int main()
  14. {
  15. #ifdef io_test
  16.     freopen("in.txt","r",stdin);
  17.     freopen("out.txt","w",stdout);
  18. #endif // io_test
  19.     //int n,m;
  20.     int t;
  21.     while(scanf("%d",&t)==){
  22.         ll x,y,z,a,b,c;
  23.         //queue<struct pot>pq;
  24.         scanf("%lld%lld%lld%lld%lld%lld",&x,&a,&y,&b,&z,&c);
  25.         ll l,r,temp,A;
  26.         scanf("%lld%lld%lld%lld",&l,&r,&temp,&A);
  27.         int head=;
  28.         int tail=;
  29.         for(int i=;i<=t;i++){
  30.             dp[i]=dp[i-];
  31.             if(i>=x){
  32.                 dp[i]=max(dp[i],dp[i-x]+a);
  33.             }
  34.             if(i>=y){
  35.                 dp[i]=max(dp[i],dp[i-y]+b);
  36.             }
  37.             if(i>=z){
  38.                 dp[i]=max(dp[i],dp[i-z]+c);
  39.             }
  40.             if(i>=l){
  41.                 while((head+<=tail&&(i-pq[head]>r||(dp[pq[head+]]-dp[pq[head]]>(pq[head+]-pq[head])*A))))head++;
  42.                 if(head<=tail){
  43.                     dp[i]=max(dp[i],dp[pq[head]]+temp+A*(i-pq[head]-l));
  44.                 }
  45.                 while(tail-head>=&&(dp[i-l+]-dp[pq[tail]])*(pq[tail]-pq[tail-])>(i-l+-pq[tail])*(dp[pq[tail]]-dp[pq[tail-]]))tail--;//维护凸包
  46.                 ++tail;
  47.                 pq[tail]=i-l+; 
  48.             }
  49.         }
  50.         printf("%lld\n",dp[t]);
  51.     }
  52.     return ;
  53. }

单调队列优化dp

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<vector>
  6. #include<queue>
  7. #include<map>
  8. using namespace std;
  9. //#define io_test
  10. #define debug(x) cout<<x<<"####"<<dp[x][0]<<"##"<<dp[x][1]<<endl;
  11. typedef long long ll;
  12. ll dp[],pq[];
  13. int main()
  14. {
  15. #ifdef io_test
  16.     freopen("in.txt","r",stdin);
  17.     freopen("out.txt","w",stdout);
  18. #endif // io_test
  19.     //int n,m;
  20.     int t;
  21.     while(scanf("%d",&t)==){
  22.         ll x,y,z,a,b,c;
  23.         //queue<struct pot>pq;
  24.         scanf("%lld%lld%lld%lld%lld%lld",&x,&a,&y,&b,&z,&c);
  25.         ll l,r,temp,A;
  26.         scanf("%lld%lld%lld%lld",&l,&r,&temp,&A);
  27.         int head=;
  28.         int tail=;
  29.         for(int i=;i<=t;i++){
  30.             dp[i]=dp[i-];
  31.             if(i>=x){
  32.                 dp[i]=max(dp[i],dp[i-x]+a);
  33.             }
  34.             if(i>=y){
  35.                 dp[i]=max(dp[i],dp[i-y]+b);
  36.             }
  37.             if(i>=z){
  38.                 dp[i]=max(dp[i],dp[i-z]+c);
  39.             }
  40.             if(i>=l){
  41.                 while((head+<=tail&&(i-pq[head]>r||(dp[pq[head+]]-dp[pq[head]]>(pq[head+]-pq[head])*A))))head++;
  42.                 if(head<=tail){
  43.                     dp[i]=max(dp[i],dp[pq[head]]+temp+A*(i-pq[head]-l));
  44.                 }
  45.                 while(tail>=head&&(dp[i-l+]-dp[pq[tail]])>A*(dp[i-l+]-dp[pq[tail]]))tail--;//维护单调队列
  46.                 ++tail;
  47.                 pq[tail]=i-l+; 
  48.             }
  49.         }
  50.         printf("%lld\n",dp[t]);
  51.     }
  52.     return ;
  53. }

这题还有一个背包的写法,因为大招的伤害和时间的关系是条直线,所以最后的结果一定是若干小技能+若干次不蓄力大招+若干次蓄满力大招+一次不满的大招(注意只会使用一次不满的大招,这点决定了可以直接背包而不会T掉),也就是说真正需要暴力枚举的大招时间只有一次,也就是那次没有满的大招,所以复杂度就是O(N)

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<vector>
  6. #include<queue>
  7. #include<map>
  8. using namespace std;
  9. //#define io_test
  10. #define debug(x) cout<<x<<"####"<<dp[x][0]<<"##"<<dp[x][1]<<endl;
  11. typedef long long ll;
  12. ll dp[],pq[];
  13. int main()
  14. {
  15. #ifdef io_test
  16. freopen("in.txt","r",stdin);
  17. freopen("out.txt","w",stdout);
  18. #endif // io_test
  19. //int n,m;
  20. int t;
  21. while(scanf("%d",&t)==){
  22. ll x,y,z,a,b,c;
  23. //queue<struct pot>pq;
  24. scanf("%lld%lld%lld%lld%lld%lld",&x,&a,&y,&b,&z,&c);
  25. ll l,r,temp,A;
  26. scanf("%lld%lld%lld%lld",&l,&r,&temp,&A);
  27. int head=;
  28. int tail=;
  29. for(int i=;i<=t;i++){
  30. dp[i]=dp[i-];
  31. if(i>=x){
  32. dp[i]=max(dp[i],dp[i-x]+a);
  33. }
  34. if(i>=y){
  35. dp[i]=max(dp[i],dp[i-y]+b);
  36. }
  37. if(i>=z){
  38. dp[i]=max(dp[i],dp[i-z]+c);
  39. }
  40. if(i>=l){
  41. dp[i]=max(dp[i],dp[i-l]+temp);
  42. }
  43. if(i>=r){
  44. dp[i]=max(dp[i],dp[i-r]+temp+A*(r-l));
  45. }
  46. }
  47. for(int i=l;i<=r;i++){//未满的大招只有一次,所以只进行一次枚举更新
  48. if(t>=i)dp[t]=max(dp[t],dp[t-i]+temp+A*(i-l));
  49. }
  50. printf("%lld\n",dp[t]);
  51. }
  52. return ;
  53. }

[小明打联盟][斜率/单调队列 优化dp][背包]的更多相关文章

  1. Parade(单调队列优化dp)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    ...

  2. BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP

    BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP Description 有一排n棵树,第i棵树的高度是Di. MHY要从第一棵树到第n棵树去找他的妹子玩. 如果MHY在 ...

  3. 算法笔记--单调队列优化dp

    单调队列:队列中元素单调递增或递减,可以用双端队列实现(deque),队列的前面和后面都可以入队出队. 单调队列优化dp: 问题引入: dp[i] = min( a[j] ) ,i-m < j ...

  4. 【bzoj3831】[Poi2014]Little Bird 单调队列优化dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6826475.html 题目描述 In the Byteotian Line Forest there are   t ...

  5. 动态规划专题(四)——单调队列优化DP

    前言 单调队列优化\(DP\)应该还算是比较简单容易理解的吧,像它的升级版斜率优化\(DP\)就显得复杂了许多. 基本式子 单调队列优化\(DP\)的一般式子其实也非常简单: \[f_i=max_{j ...

  6. 单调队列优化DP || [NOI2005]瑰丽华尔兹 || BZOJ 1499 || Luogu P2254

    题外话:题目极好,做题体验极差 题面:[NOI2005]瑰丽华尔兹 题解: F[t][i][j]表示第t时刻钢琴位于(i,j)时的最大路程F[t][i][j]=max(F[t-1][i][j],F[t ...

  7. 【笔记篇】单调队列优化dp学习笔记&&luogu2569_bzoj1855股票交♂易

    DP颂 DP之神 圣洁美丽 算法光芒照大地 我们怀着 崇高敬意 跪倒在DP神殿里 你的复杂 能让蒟蒻 试图入门却放弃 在你光辉 照耀下面 AC真心不容易 dp大概是最经久不衰 亘古不化的算法了吧. 而 ...

  8. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  9. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

随机推荐

  1. css的position

    1.标准流2.浮动3.定位块级元素:div.H1-H6.有序及无序列表(ol.ul.li).p内联元素:a.span.img 1. 介绍 1.1 说明 Position 属性:规定元素的定位类型.即元 ...

  2. Vmware网络不可达

    1. ifconfig -a   查看当前的网卡 2. cd  /etc/sysconfig/network-scripts/ 3. 打开对应网卡名称文件, 具体修改内容参考(https://www. ...

  3. DevExpress WinForms使用教程:皮肤颜色和LookAndFeel

    [DevExpress WinForms v18.2下载] v18.2版本中更改了控制背景颜色和皮肤一起处理的方式.在v18.1中引入了Project Settings页面,其中包含一个skin se ...

  4. AJAX的简单示例:注册校验

    众所周知,我们每次需要注册一个网站的用户名时,都会校验该邮箱.用户名是不是正确的格式.是不是有被使用过,密码是否符合规则,二次确认是否符合. 如果这些校验都采用form表单提交的话,会给用户带来极不好 ...

  5. 小白的REDIS学习(二)-链表

    本文为读<Redis设计与实现>的记录.该书以Redis2.9讲解Redis相关内容.请注意版本差异. Redis使用C语言,实现了自己的链表结构,实现的代码如下 //集成了链表的各类信息 ...

  6. elasticsearch(4) 轻量搜索

    一 空搜索 搜索API的最基础的形式是没有指定任何查询的空搜索 ,它简单地返回集群中所有索引下的所有文档: 示例 GET 127.0.0.1:9200/_search 响应 { , "tim ...

  7. Maven Gradle

    场景:随着项目越来越规范,对构建工具的要求越来越高,我们从Maven转到了Gradle. 转自:http://www.infoq.com/cn/news/2011/04/xxb-maven-6-gra ...

  8. js date setInterval 时间 时钟 getFullYear ,JavaScript

    js 创建时钟: 1.参考链接:  注意 getYear  (两位 或者 四位) 改成 getFullYear js操作时间 2.实例: html: <span class="glyp ...

  9. 超低质量的超低起点PYQT ------前言

    由于年后要赶一个小工程,以前一直用VB6+sqL2K的做些小玩具一样的桌面项目,低级的不能再低级了,某日幡然醒悟,决定努力跟进潮流的尾巴..匆匆撸了一遍网上的PYTHON基础知识,面向对象,装饰器.. ...

  10. C语言---指针变量详解1

    数据在内存中的地址也称为指针,如果一个变量存储了一份数据的指针,我们就称它为指针变量.在C语言中,允许用一个变量来存放指针,这种变量称为指针变量.指针变量的值就是某份数据的地址,这样的一份数据可以是数 ...