题目描述

经过小FF的研究,他发现蚂蚁们每次都走同一条长度为n个单位的路线进攻, 且蚂蚁们的经过一个单位长度所需的时间为T秒。也就是说,只要小FF在条路线上布防且给蚂蚁造成沉痛伤害就能阻止蚂蚁的进军。

SCV擅长制造的防御塔有三种,分别是激光塔,放射塔和干扰塔, 他们可以在一个单位长度内修建一座防御塔。三种防御塔的作用如下:

激光塔: 使用高能激光,当蚂蚁从塔前经过时每秒对蚂蚁造成r点伤害。

放射塔: 释放放射性元素, 当蚂蚁经过这座塔后,每一秒受到g点伤害。

干扰塔: 干扰塔负责干扰蚂蚁们的信息素,使得蚂蚁在经过这座塔后,经过之后每一个单位长度的时间变成T+b。

当然, 放射塔和干扰塔的效果是可以叠加的, 也就是说如果敌人经过x座放射塔,那么敌人每秒钟会受到x * g点伤害; 同理,如果敌人经过y座干扰塔, 那么敌人经过一个单位长度的时间将变为T+y * b。

现在距离蚂蚁的下一轮进攻还有足够长的时间,你这个“NewBe_One”计划的首席工程师现在被任命为战略总参谋长, 因此你必须设计一个给蚂蚁们造成最大伤害的布塔方案。

输入格式

输入数据仅一行, 5个整数 n, r, g, b, T中间用一个空格隔开。 它们分别表示你可以布防的总长度, 激光塔的效果、 放射塔的效果和干扰塔的效果。

对于30%的数据: 1<=n<=20;

对于60%的数据: 1<=n<=1024;0<=r, g, b<=65536;0<=T<=3;

对于另外40%的数据:1<=n<=400;0<=r, g, b<=2^31-1;0<=t<=1000.

输出格式

输出仅一个整数, 代表你的方案给敌人带来的最大伤害值。


我们先逮着400的数据下手:

这道题最好想的就是动态规划了,几个状态一开出来直接转移即可。首先设dp(i,j,k,l,0/1/2),其中i表示当前在第i个位置,已经放置了j个放射塔,并且放了k个干扰塔和l个激光塔,0表示i这个位置放放射塔,1表示干扰塔,2表示激光塔。先不管爆内存的事,列出状态转移方程:

\[dp[i][j][k][l][0]=Max_{0≤x≤2}{\{}dp[i-1][j-1][k][l][x]{\}}+g*(j-1)*(t+k*b)\\
dp[i][j][k][l][1]=Max_{0≤x≤2}{\{}dp[i-1][j][k-1][l][x]{\}}+g*j*(t+(k-1)*b)\\
dp[i][j][k][l][2]=Max_{0≤x≤2}{\{}dp[i-1][j][k][l-1][x]{\}}+(g*j+r)*(t+k*b)
\]

可以发现每个状态都由上一个状态的最大值更新而来,所以我们可以省掉最后一维,让dp数组自带Max:

\[ans0=dp[i-1][j-1][k][l]+g*(j-1)*(t+k*b)\\
ans1=dp[i-1][j][k-1][l]+g*j*(t+(k-1)*b)\\
ans2=dp[i-1][j][k][l-1]+(g*j+r)*(t+k*b)\\
dp[i][j][k][l]=Max{\{}ans0,ans1,ans2{\}}
\]

然后我们发现,更新dp数组时我们只需要用到第i-1和第i位的信息,i-2及之前的地方都浪费了,所以我们可以把它滚掉:

\[ans0=dp[!d][j-1][k][l]+g*(j-1)*(t+k*b)\\
ans1=dp[!d][j][k-1][l]+g*j*(t+(k-1)*b)\\
ans2=dp[!d][j][k][l-1]+(g*j+r)*(t+k*b)\\
dp[d][j][k][l]=Max{\{}ans0,ans1,ans2{\}},d{\in}[0,1]
\]

然后我们又发现,每个位置必须放一个塔,不然显然没有防塔的优。那么当我们枚举到i这个位置时,我们可以由i-j-k推出l的值。所以我们只需要三层循环就够了。并且由于j,k确定之后,l也是确定的,那么我们可以干脆掐掉l这一维:

\[ans0=dp[!d][j-1][k]+g*(j-1)*(t+k*b)\\
ans1=dp[!d][j][k-1]+g*j*(t+(k-1)*b)\\
ans2=dp[!d][j][k]+(g*j+r)*(t+k*b)\\
dp[d][j][k]=Max{\{}ans0,ans1,ans2{\}},d{\in}[0,1]
\]

然后经过提交发现,d这一维要不要都无所谓。其实感性地证明一下也是可以得出这个结论的。那么:

\[ans0=dp[j-1][k]+g*(j-1)*(t+k*b)\\
ans1=dp[j][k-1]+g*j*(t+(k-1)*b)\\
ans2=dp[j][k]+(g*j+r)*(t+k*b)\\
dp[j][k]=Max{\{}ans0,ans1,ans2{\}}
\]

那么最初级的算法就设计出来了,时间复杂度为O(N^3)。然后发现开O2可以过?


N^3显然不是正解。

我们看到上面暴力的最终转移方程,可以发现我们的dp数组只与放置的塔的个数有关,与当前在哪个位置无关,那么可以这么认为:上面的暴力算法中枚举位置时其实是在确定激光塔的数量。所以说我们只需要枚举j和k,而l可以直接n-j-k得出,所以我们只需要两层循环。不过伤害值怎么算?

我们分析一下题目:

如果我们在中间放下激光塔,即它的后面还有放射塔和干扰塔,那么可以发现我们把随便一个后面的放射塔和干扰塔拿来给激光塔换一下都会更优。进一步我们得出一个结论:激光塔必定放在末尾的位置,并且是连续的一串激光塔。

所以我们可以枚举了j和k之后直接根据j和k算出激光塔的伤害了。具体看代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 1025
using namespace std; __int128 dp[maxn][maxn];
__int128 n,r,g,b,t;
__int128 ans; inline __int128 read(){
register __int128 x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
} void print(__int128 x){
if(!x) return;
print(x/10);
putchar(x%10+'0');
} int main(){
n=read(),r=read(),g=read(),b=read(),t=read();
//先计算放射塔和干扰塔的伤害,激光塔最后算
for(register int i=1;i<=n;i++){
for(register int j=0;i+j<=n;j++){
if(!j) dp[i][j]=dp[i-1][j]+g*(i-1)*(t+j*b);
else dp[i][j]=max(dp[i-1][j]+g*(i-1)*(t+j*b),dp[i][j-1]+g*i*(t+(j-1)*b));
}
}
//找最大值作为答案,并且加上激光塔的伤害
for(register int i=0;i<=n;i++){
for(register int j=0;i+j<=n;j++){
register int k=n-i-j;
if(k) ans=max(ans,dp[i][j]+(g*i+r)*k*(t+j*b));
}
}
print(ans);
return 0;
}

* 数据需要开高精,为了可读性(和懒)代码用了__int128。

luogu P2198 杀蚂蚁的更多相关文章

  1. Luogu2586 [ZJOI2008]杀蚂蚁 ---- 模拟

    Luogu2586 [ZJOI2008]杀蚂蚁 题意 还是一道大模拟 https://www.luogu.org/problemnew/show/P2586 大概就是炮塔大蚂蚁的故事 下载这个游戏ht ...

  2. 【BZOJ 1033】 [ZJOI2008]杀蚂蚁antbuster

    Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任 ...

  3. BZOJ 1033 杀蚂蚁

    Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任 ...

  4. bzoj千题计划121:bzoj1033: [ZJOI2008]杀蚂蚁antbuster

    http://www.lydsy.com/JudgeOnline/problem.php?id=1033 经半个下午+一个晚上+半个晚上 的 昏天黑地调代码 最终成果: codevs.洛谷.tyvj上 ...

  5. [BZOJ 1033][ZJOI2008]杀蚂蚁antbuster

    1033: [ZJOI2008]杀蚂蚁antbuster Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1200  Solved: 507[Submi ...

  6. BZOJ1033:[ZJOI2008]杀蚂蚁antbuster(模拟)

    Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右 下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的 ...

  7. [bzoj1033] [ZJOI2008]杀蚂蚁antbuster

    Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任 ...

  8. BZOJ1033:[ZJOI2008]杀蚂蚁

    我对模拟的理解:https://www.cnblogs.com/AKMer/p/9064018.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem ...

  9. [ZJOI2008]杀蚂蚁

    题意翻译 注意在(0,0)已经有蚂蚁的时候是不会生成新蚂蚁的 还有如果有蚂蚁扛着蛋糕,但是不在某个炮的范围内,炮仍然会打最近的蚂蚁 题目描述 最近,佳佳迷上了一款好玩的小游戏:antbuster. 游 ...

随机推荐

  1. Spark性能调优篇七之JVM相关参数调整

    降低cache操作的内存占比 方案: 通过SparkConf.set("spark.storage.memoryFraction","0.6")来设定.默认是0 ...

  2. 小白数据分析——Python职位全链路分析

    最近在做Python职位分析的项目,做这件事的背景是因为接触Python这么久,还没有对Python职位有一个全貌的了解.所以想通过本次分析了解Python相关的职位有哪些.在不同城市的需求量有何差异 ...

  3. JDK8新特性详解(二)

    Stream流的使用 流操作是Java8提供一个重要新特性,它允许开发人员以声明性方式处理集合,其核心类库主要改进了对集合类的 API和新增Stream操作.Stream类中每一个方法都对应集合上的一 ...

  4. C#常用的算法

    一.二分法 注:一定是有序的数组,才可以使用这种算法,如果数组没有排序则先进行排序后再调用此方法. 二分顾名思义,就是将一组数据对半分开(比如左右两部分,下面用左右数组表示),从中间位置开始查找, 如 ...

  5. Excel 多/整列(多/整行)移位操作

    步骤1:创建测试数据 步骤2:把B列和C列进行移位操作(整列移位操作,多列移位操作方法一样) 选中B列,鼠标放到B列边缘地带,直到鼠标显示带有四个箭头方向为止,点击键盘shift键进行拖拽,拖拽时显示 ...

  6. 【进程/作业管理】篇章一:Linux进程及其管理(进程管理类工具)----pstree、ps、top、htop、kill、(killall、pkill、pgrep、pidof)

    主要讲解进程管理类命令及工具的使用:pstree.ps.top.htop.kill.(killall.pkill.pgrep.pidof) pstree 以树状图的方式展现进程之间的派生关系,显示效果 ...

  7. spring boot编程思想(核心篇) pdf 下载 it教程

    资料简介:本书是<Spring Boot 编程思想>的核心篇,开篇总览Spring Boot核心特性,接着讨论自动装配(Auto-Configuration)与SpringApplicat ...

  8. Mac电脑 Android Studio连接小米手机

    1.设置>关于本机>点击5下MIUI版本>激活开发者模式 2.设置>更多设置>开发者选项>开启开发者选项>开启USB调试>开启USB安装>开启显示 ...

  9. JSP 的 4 种作用域?

    page:代表与一个页面相关的对象和属性. request:代表与客户端发出的一个请求相关的对象和属性.一个请求可能跨越多个页面,涉及多个 Web 组件:需要在页面显示的临时数据可以置于此作用域. s ...

  10. 关于STM32的CAN的过滤器

    关于STM32的CAN的过滤器STM32普通型芯片的CAN有14组过滤器组,互联型有28组过滤器组.一般我们用的都是普通型的,所以在本文中可以说STM32有14组过滤器组.根据配置,每1组过滤器组可以 ...