5 倍经验日
题目背景
现在乐斗有活动了!每打一个人可以获得 5 倍经验!absi2011 却无奈的看着那一些比他等级高的好友,想着能否把他们干掉。干掉能拿不少经验的。
题目描述
现在 absi2011 拿出了 个迷你装药物(嗑药打人可耻…),准备开始与那些人打了。
由于迷你装药物每个只能用一次,所以 absi2011 要谨慎的使用这些药。悲剧的是,用药量没达到最少打败该人所需的属性药药量,则打这个人必输。例如他用 个药去打别人,别人却表明 个药才能打过,那么相当于你输了并且这两个属性药浪费了。
现在有 个好友,给定失败时可获得的经验、胜利时可获得的经验,打败他至少需要的药量。
要求求出最大经验 ,输出 。
输入格式
第一行两个数, 和 。
后面 行每行三个数,分别表示失败时获得的经验 ,胜利时获得的经验 和打过要至少使用的药数量 。
输出格式
一个整数,最多获得的经验的五倍。
样例 #1
样例输入 #1
6 8
21 52 1
21 70 5
21 48 2
14 38 3
14 36 1
14 36 2
样例输出 #1
1060
提示
【Hint】
五倍经验活动的时候,absi2011 总是吃体力药水而不是这种属性药。
【数据范围】
- 对于 的数据,保证 。
- 对于 的数据,保证 ,。
- 对于 的数据,保证 , ,。
- 对于 的数据,保证 ,,。
【题目来源】
fight.pet.qq.com
absi2011 授权题目
思路
使用一个一维动态规划数组dp来记录在每个药物数量下能够获得的最大经验值。对于每一个好友(物品),我们从药物数量开始向下遍历到0。
如果当前的药物数量大于或等于打败好友所需的药量,那么我们有两种选择:
-
直接失败,获得基础经验
dp[j] + l[i] -
消耗的药物打败好友,获得胜利经验。我们选择这两种方案中经验值更大的那个。
dp[j - u[i]] + w[i]
得到状态转移方程:
dp[j] = max(dp[j] + l[i], dp[j - u[i]] + w[i]);
如果当前的药物数量小于打败好友所需的药量,那么我们只能选择失败,获得基础经验。
dp[j] += l[i];
注意:
- 输出的是最大经验值乘以5,这是因为题目中提到了“每打一个人可以获得 5 倍经验”。
- 被打败后不是扣除经验值,而是获得失败时可获得的经验。不要把状态转移方程写成:
dp[j] = max(dp[j] - l[i], dp[j - u[i]] + w[i]);
AC代码
#include <algorithm>
#include <iostream>
#define ll long long
#define AUTHOR "HEX9CF"
using namespace std;
const int N = 1e7 + 7;
int n, x;
ll dp[N];
int l[N], w[N], u[N];
int main() {
cin >> n >> x;
for (int i = 1; i <= n; i++) {
cin >> l[i] >> w[i] >> u[i];
}
for (int i = 1; i <= n; i++) {
for (int j = x; j >= 0; j--) {
if (j >= u[i]) {
dp[j] = max(dp[j] + l[i], dp[j - u[i]] + w[i]);
} else {
dp[j] += l[i];
}
}
}
cout << 5 * dp[x] << endl;
return 0;
}