问题描述
火神为了训练,决定单挑 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 a−b×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
1≤n≤10。
对于
50
%
50\%
50% 的数据,
1
≤
n
≤
18
1 \le n \le 18
1≤n≤18。
对于
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
1≤n≤1000,1≤t≤3000,1≤Ci≤t,1≤Ai≤106。
对于
n
≤
200
n \le 200
n≤200 的数据,
1
≤
T
≤
10
1 \le T \le 10
1≤T≤10。
对于
n
>
200
n > 200
n>200 的数据,
1
≤
T
≤
5
1 \le T \le 5
1≤T≤5。
保证每个人贡献的经验值到训练结束都不会变成负数。
题解
首先,我们先确定 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(fi−Cj+Aj−i×Bj)(i≤j≤n)。
答案就是 m a x ( f i ) ( 0 ≤ i ≤ t ) max(f_i)(0 \le i \le t) max(fi)(0≤i≤t)。
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);
}
}