题面 :幸苦的工作(Work.cpp)

题目描述

​ 在工作中,小明有 $n$ 个任务要完成。第个任务有一个基础时间t和额外时间 $p_i$。( $t$ 是互不相同的,$p_i$ 也是互不相同的)
​ 如果在做任务之前小明已经做了 $k$ 个任务,则做这个任务需要 $t+k·p$ 的时间(因为任务繁重,小明累了)现在小明还剩下的时间为 $T$ ,请问他在这段时间内最多能做多少个任务(假定任务之间没有依赖关系)。(题目保证 $t,p$ 不重)

思路:暴搜 & DP (劣) & DP (std)

首先的,暴力枚举每个工作的顺序,求答案。代码略(伪代码也别想要)

然后我们开始考虑正解,这道题,一眼丁真就是 DP 。关键在于怎么 DP 。突然发现有点像背包,而且 $t$ 和 $p$ 不重发现完全是可以在 1000 以内完成,给人物按照 $p$ 排序,跑背包即可。

代码:正解代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
typedef long long ll;

int n, T;
struct Node {
ll t, p;
friend bool operator <(Node &a, Node& b) {
return a.p > b.p;
}
}a[N];

ll dp[N];

void Input() {
scanf("%d%d", &n, &T);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i].t);
}
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i].p);
}
}

void Work() {
sort(a + 1, a + n + 1);
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1000; j >= 1; j--) {
dp[j] = min(dp[j], dp[j - 1] + a[i].t + a[i].p * (j - 1));
}
}
for (int i = n; i >= 0; i--) {
if (dp[i] <= T) {
printf("%d", i);
break;
}
}
}

int main() {
Input();
Work();
return 0;
}