【DP】【高精度】杀蚂蚁

题目链接

题目背景

说“善有善报,恶有恶报,不是不报……”。 小FF一心只顾自己企业的壮大而没顾及自己的采矿业对Greed Island上生态环境的破坏, Greed Island的环境日益恶劣。 终于,岛上的蚂蚁们变异了,它们决定对小FF的矿区进行攻击,欲将岛上的人类驱逐出去……面对蚂蚁们的进攻, 人类节节败退。无奈之下, 小FF请来了全宇宙最强的防御系统制造商派来的工程机器人——SCV,希望能够阻挡蚂蚁的攻势。

题目描述

经过小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.

输出

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

输入样例

5 4 3 2 1

输出样例

82

分析

首先我们要搞清楚题意。

题目中给了我们三种塔:

激光塔:蚂蚁经过时每秒r点伤害

放射塔:蚂蚁经过后每秒g点伤害,效果可累加

干扰塔:蚂蚁经过后速度变为T + b,效果可累加

激光塔对于位置没有什么要求,而干扰塔和放射塔很明显是越靠前所造成的总伤害越高,而单纯的干扰塔并不能对蚂蚁造成伤害,所以最终的方案一定是以一堆放射塔,一堆干扰塔,一堆激光塔的形式存在。

想明白了这一点,我们来思考这道题怎么做。

那么接下来我们要做的就是枚举每种塔的数量,然后求出最大伤害值

我们考虑使用DP来实现这个过程。

因为三种塔的数量总和一定为n,所以我们只需要将状态设计成两维。

用dp[ i ][ j ]来表示放了i个干扰塔,j个放射塔对蚂蚁造成的伤害

那么状态转移方程就比较清晰了:

dp[i][j] = max(dp[i - 1][j] + g * j * b * k, dp[i][j - 1] + g * (t + i * b) * k);

其中g * j * b * k表示增加一座干扰塔增加的伤害,g * (t + i * b) * k)表示增加一座放射塔造成的伤害。

那么,最后的答案就很好求了

ans = max(dp[i][j] + r * (t + i * b) * k)

r * (t + i * b) * k)表示增加一座激光塔的伤害

这道题比较不和谐的一点是它需要写高精。。不过被本蒟蒻使用__int128和谐掉了QAQAQ。

代码(__int128)

#include<bits/stdc++.h>
using namespace std;
__int128 n, r, g, b, t, ans;
__int128 dp[1050][1050];

inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
    return x * f;
}

void print(__int128 x) {
    if (x > 9) print(x / 10);
    putchar(x % 10 + '0');
}

int main() {
    n = read(), r = read(), g = read(), b = read(), t = read();
    for (int i = 1; i <= n; i++) {
	dp[0][i] = dp[0][i - 1] + (n - i) * g * t;
    }
    for (int i = 1; i < n; i++) {
	for (int j = 1, k; k = n - i - j; j++) {
	    dp[i][j] = max(dp[i - 1][j] + g * j * b * k, dp[i][j - 1] + g * (t + i * b) * k);
	}
    }
    for (int i = 0; i <= n; i++) {
	for (int j = 0; j <= n - i; j++) {
	    int k = n - i - j;
	    if (k < 0) continue;
	    ans = max(ans, dp[i][j] + r * (t + i * b) * k);
	}
    }
    print(ans);
}

emmmmm后面我打个高精的贴上来吧。。今天休息。。

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值