[贪心 + dp] 疯狂的火神

问题描述

火神为了训练,决定单挑 n n n 个人。

由于火神训练时间有限,最多只有 t t t 分钟,所以他可以选择一部分人来单挑,由于有丽子的帮助,他得到了每个人特定的价值,每个人的价值由一个三元组 ( a , b , c ) (a, b, c) (a,b,c) 组成,表示如果火神在第 x x x 分钟打倒了这个人,他就会得到 a − b × x a - b \times x ab×x 的经验值,当前这个人他需要 c c c 分钟来打倒。

现在火神想知道,他最多可以得到多少经验值,由于火神本来就很笨,所以他希望你来帮他计算出他最多可以得到多少经验值。

输入格式

第一行一个正整数 T T T ,表示数据组数。
对于每组数据,第一行为两个正整数 n n n t t t ,表示跟火神单挑的人的个数和火神的训练时间。
下面 n n n 行,每行三个正整数 A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci ,表示每个人的价值,含义见题目。

输出格式

对于每组数据输出一行一个整数表示火神最多能得到多少经验值。

样例

样例输入1:

1
4 10
110 5 9
30 2 1
80 4 8
50 3 2

样例输出1:

88

数据范围

对于 20 % 20\% 20% 的数据, 1 ≤ n ≤ 10 1 \le n \le 10 1n10
对于 50 % 50\% 50% 的数据, 1 ≤ n ≤ 18 1 \le n \le 18 1n18
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1000 , 1 ≤ t ≤ 3000 , 1 ≤ C i ≤ t , 1 ≤ A i ≤ 1 0 6 1 \le n \le 1000, 1 \le t \le 3000, 1 \le C_i \le t, 1 \le A_i \le 10^6 1n1000,1t3000,1Cit,1Ai106

对于 n ≤ 200 n \le 200 n200 的数据, 1 ≤ T ≤ 10 1 \le T \le 10 1T10
对于 n > 200 n > 200 n>200 的数据, 1 ≤ T ≤ 5 1 \le T \le 5 1T5

保证每个人贡献的经验值到训练结束都不会变成负数。

题解

首先,我们先确定 m m m 个人单挑,再确定顺序。

先确定 m m m 个人,假设他们分别是 x 1 , x 2 , … x n x_1, x_2, \ldots x_n x1,x2,xn

交换 x i x_i xi x i + 1 x_{i + 1} xi+1,交换前损失了 C x i × B x i + 1 + K C_{x_i} \times B_{x_{i + 1}} + K Cxi×Bxi+1+K K K K 是另外位置的值),交换后损失了 C x i + 1 × B x i + K C_{x_{i + 1}} \times B_{x_i} + K Cxi+1×Bxi+K

因此,只需考虑 C x i × B x i + 1 + K C_{x_i} \times B_{x_{i + 1}} + K Cxi×Bxi+1+K C x i + 1 × B x i + K C_{x_{i + 1}} \times B_{x_i} + K Cxi+1×Bxi+K 的大小,如果 C x i × B x i + 1 + K > C x i + 1 × B x i + K C_{x_i} \times B_{x_{i + 1}} + K > C_{x_{i + 1}} \times B_{x_i} + K Cxi×Bxi+1+K>Cxi+1×Bxi+K,就要交换。简化一下就是 C x i × B x i + 1 > C x i + 1 × B x i C_{x_i} \times B_{x_{i + 1}} > C_{x_{i + 1}} \times B_{x_i} Cxi×Bxi+1>Cxi+1×Bxi,即 B x i + 1 C x i + 1 > B x i C x i \frac{B_{x_{i + 1}}}{C_{x_{i + 1}}} > \frac{B_{x_i}}{C_{x_i}} Cxi+1Bxi+1>CxiBxi

排完序后,用动态规划解决。

f i f_i fi 表示第 i i i 分钟的最高经验值,状态转移为 f i = m a x ( f i − C j + A j − i × B j ) ( i ≤ j ≤ n ) f_i = max(f_{i - C_j} + A_j - i \times B_j)(i \le j \le n) fi=max(fiCj+Aji×Bj)(ijn)

答案就是 m a x ( f i ) ( 0 ≤ i ≤ t ) max(f_i)(0 \le i \le t) max(fi)(0it)

int T;
int n, m;
struct node{
	int x, y, z;//x, y, z 对应 a, b, c
}a[1010];
bool cmp(node p, node q){
	return p.y * q.z > p.z * q.y;
}
int f[3010];//dp
int ans = 0;
int main(){
	scanf("%d", &T);
	while(T --){
		ans = 0;
		memset(f, 0, sizeof(f));
		输入
		sort(a + 1, a + n + 1, cmp);
		//dp
		for(int i = 1; i <= n; ++ i){
			for(int j = m; j >= a[i].z; -- j){
				f[j] = max(f[j - a[i].z] + a[i].x - j * a[i].y, f[j]);
			}
		}
		for(int i = 1; i <= m; ++ i){
			ans = max(ans, f[i]);
		}
		printf("%d\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值