首页 > 其他分享 >P2198 杀蚂蚁 题解

P2198 杀蚂蚁 题解

时间:2024-01-13 17:36:09浏览次数:39  
标签:蚂蚁 int 题解 times read P2198 放射 dp

题目大意

有一条长度为 \(n\) 个单位长度的路,蚂蚁们要从起点走到终点。蚂蚁们每走 \(1\) 个单位距离需要 \(T\) 秒钟。现在,出题人可以在路上修筑 \(3\) 种防御塔来阻挡蚂蚁的进攻,每个单位距离只能修筑 \(1\) 座塔,塔的作用分别如下:

  1. 激光塔:蚂蚁在塔前时每秒会受到 \(r\) 点伤害。

  2. 放射塔:蚂蚁经过塔后,每秒钟受到 \(g\) 点伤害。

  3. 干扰塔:蚂蚁经过塔后,每行走一个单位距离的时间延长为 \(T + b\)。

其中,放射塔和干扰塔的效果可以叠加。比如蚂蚁经过了 \(y\) 座放射塔后,每秒钟受到的伤害为 \(yr\),干扰塔同理。

现在需求能给蚂蚁们造成的最大伤害。

解法

分析题目,题目需要求一个最大值,且不在意中间过程,因此我们可以考虑 dp。

设 \(dp_{i, j, k}\) 表示修 \(i\) 座干扰塔,\(j\) 座放射塔,\(k\) 座激光塔的最大伤害。显然,每个位置都修塔是最优的,因此,我们可以省掉一维 \(k\),需要用时直接计算即可。

关于如何转移,枚举干扰塔和放射塔的个数 \(i, j\),\(dp_{i, j}\) 可以由 \(dp_{i - 1, j}, dp_{i, j - 1}\) 转移过来,也就是对于上一个状态来说,少一座激光塔,多一座干扰塔或少一座激光塔,多一座放射塔。那么 \(dp_{i, j} = \max(dp_{i - 1, j} - r\times(t + b(i - 1)) + b\times(n - i - j)(r + g\times j), dp_{i, j - 1} - t\times r - i\times b\times r + g\times(n - i - j)(t + b\times i)\)。多一座干扰塔,就要将一座激光塔所造成的伤害减去,加上时间延长放射塔所造成的伤害。多一座放射塔,也要讲一座激光塔的伤害减去,然后加上一座放射塔所造成的伤害。

边界的处理和转移差不多,就是此时只有两种塔,比转移少简单一些。需要注意的是全是激光塔的情况也需要处理,也就是 \(dp_{0, 0} = t\times r\times n\)。

由于此题答案可能过大,整数变量需要定义为 __int128,且 __int128 无法使用 cincoutscanfprintf 等进行输入输出,所以请手写快读快写。

AC Code

#include<bits/stdc++.h>
#define int __int128
using namespace std;
const int N = 2e3 + 5;
int n, r, g, b, t, dp[N][N], ans;
int read()
{
	int k = 1, t = 0;
	char c = getchar();
	while(c < '0' || c > '9')
	{
		if(c == '-')
			k *= -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9')
	{
		t = t * 10 + c - '0';
		c = getchar();
	}
	return k * t;
}
void write(int x)
{
	int b[50], cnt = 0;
	while(x != 0)
	{
		int y = x % 10;
		x /= 10;
		b[++cnt] = y;
	}
	for(int i = cnt; i >= 1; i--)
		putchar(b[i] + '0');
	return;
}
signed main()
{
	n = read(), r = read(), g = read(), b = read(), t = read();
	memset(dp, 0xcf, sizeof(dp));
	dp[0][0] = n * t * r;
	ans = dp[0][0];//处理边界
	for(int i = 1; i <= n; i++)
	{
		dp[i][0] = dp[i - 1][0] - (t + (i - 1) * b) * r + (n - i) * b * r;
		dp[0][i] = dp[0][i - 1] - t * r + (n - i) * t * g;
		ans = max(ans, max(dp[0][i], dp[i][0]));
	}
	for(int i = 1; i <= n; i++)//转移
		for(int j = 1; j + i <= n; j++)
			dp[i][j] = max(dp[i - 1][j] - (t + (i - 1) * b) * r + (n - i - j) * b * (r + g * j), dp[i][j - 1] - t * r - i * (b * r) + (n - i - j) * (t + b * i) * g);
	for(int i = 1; i <= n; i++)//答案为最大值
		for(int j = 1; j + i <= n; j++)
			ans = max(ans, dp[i][j]);
	write(ans);
	return 0;
}

标签:蚂蚁,int,题解,times,read,P2198,放射,dp
From: https://www.cnblogs.com/Luckies/p/17962642/P2198_Solution

相关文章

  • P3243 [HNOI2015] 菜肴制作 题解
    前言今天考试考到这道题,挂惨了。题意有\(n\)道菜肴,编号为\(1\simn\)。有\(m\)个条件,形如\((i,j)\),表示菜肴\(i\)必须在菜肴\(j\)之前制作。需求出一个菜肴的制作顺序,满足:在满足所有限制的前提下,\(1\)号菜肴尽量优先制作。在满足所有限制,\(1\)号菜肴尽量优......
  • P9007 [入门赛 #9] 最澄澈的空与海 (Hard Version) 题解
    Updon2023.10.1408:21:修改了推式子和题意的一些小错误。前言一道恐怖的绿题。显然我认为应该是蓝题。(不过在这篇题解写到一半的时候升蓝了,感谢@StudyingFather。)名字挺好的。题意给定\(n\),求出满足以下条件的三元组\((x,y,z)\)的组数:\(x\ge0,z\ge1\)。\(......
  • AT_abc243_g [ABC243G] Sqrt题解
    题目大意有一个数列,初始时只有一个数\(X\)。你可以对它进行一种操作:设末尾的数为\(Y\),从\(1\sim\sqrt{Y}\)中选一个数加到数列的末尾。如此进行\(10^{100}\)次操作,问数列一共有多少种可能的状态。解法考虑DP。设\(dp_i\)表示以数字\(i\)开头的数列可能的状态。设......
  • CF713D 题解
    题意给一个\(01\)矩阵,多次求在给定区间内最大的全\(1\)正方形边长。思路容易想到二分:先预处理出以每个位置为右下角的最大合法正方形的边长\(mx_{i,j}\),然后对于每个询问,我们二分边长\(mid\),设当前询问的区间左上角为\((x_1,y_1)\),右下角为\((x_2,y_2)\),则能取到\(mi......
  • AT_arc167_e 题解
    题意给定\(k\)和一个排列\(P'\),问有多少个排列\(P\)以最少步数交换相邻两个元素来进行收敛,最终的排列可能是\(P'\),一个排列是收敛的当且仅当对于每一个数,在该数前且比这个数大的数的个数不超过\(k\)个。思路考虑正向的让一个排列收敛,我们设在第\(i\)个位置前且比\(P......
  • AT_agc054_c 题解
    题意给定\(k\)和一个排列\(P'\),问有多少个排列\(P\)以最少步数交换相邻两个元素来进行收敛,最终的排列可能是\(P'\),一个排列是收敛的当且仅当对于每一个数,在该数前且比这个数大的数的个数不超过\(k\)个。思路考虑正向的让一个排列收敛,我们设在第\(i\)个位置前且比\(P......
  • P9754 题解
    题意不难理解,不多赘述。思路首先考虑对于性质A的情况,我们可以这样做:定义一个代表变量的结构体,里面存几个参数:首先肯定要存种类(\(type\))和名称(\(name\)),其次为了方便,我们把该变量的大小(\(siz\)),起始位置(\(fir\))和对齐要求(\(mx\))也存了。操作二\(type\),\(name\),\(siz\)和\(m......
  • AT_cf17_final_j 题解
    题意给定一棵既有点权也有边权的树,构造一个完全图,图中两点间边的边权为树中两点点权之和加上两点间的距离,求该图的最小生成树。思路发现完全图总边数太大,考虑减少边数。这里有一个性质:如果在一个图中选取任意个联通的边集,使得它们的并为全集,则整个图的最小生成树中的边一定在......
  • 蚂蚁爱购--靠谱的SpringBoot项目
    ​简介这是一个靠谱的SpringBoot项目实战,名字叫蚂蚁爱购。从零开发项目,视频加文档,十天就能学会开发JavaWeb项目。教程路线是:搭建环境=>安装软件=>创建项目=>添加依赖和配置=>通过表生成代码=>编写Java代码=>代码自测=>前后端联调=>准备找工作。学完即可成为合格的Java......
  • [AGC022F] Checkers 题解
    题目链接点击打开链接题目解法很妙的题!!!考虑\(x\)是无穷大的数,所以可以认为\(x^i\)的系数是单独的一项,不会和\(x^j(j\neqi)\)合并所以问题转化成了:每个数初始是\(x^i\)(\(x\)可以理解是元),进行题目中的操作,问最后形成的\(n\)次多项式的个数由\(B\)向\(A\)连边,这......