题意:有 n n n场考试,直接去考都只能得0分,现在给你一些复习资料,他们对应上述考试的一种,需要 c o s t cost cost天来阅读,阅读完之后对应的考试可以多考 v a l val val分,问有 t t t天来复习,如果挂科数不大于 p p p,最多能拿多少分
解法:进行两次dp操作
①记为
d
p
1
[
i
]
[
j
]
dp1[i][j]
dp1[i][j];
d
p
1
[
i
]
[
j
]
dp1[i][j]
dp1[i][j]表示第
i
i
i场考试获得
j
j
j分的最小花费时间,即求一个空间为
m
a
x
u
p
maxup
maxup,物品价值为天数,体积为可以增加的分数的01背包,由于考试分数上限为100,所以当两本资料提升分数之和大于100时只能算一百分,我们这里把
m
a
x
u
p
maxup
maxup设为大于两百,因为读两本资料最多就能提升200分,读两本就已经达到上限了,自然不会在读完这两本资料后花时间去读通常考试的资料。
for (int i = 1; i <= m; i++) {
int id = rmap[book[i].name];//对应的考试序号
for (int j = maxup; j >= book[i].val; j--) {
dp1[id][j] = min(dp1[id][j], dp1[id][j - book[i].val] + book[i].cost);
}
}
②记为
d
p
2
[
i
]
[
j
]
[
k
]
dp2[i][j][k]
dp2[i][j][k],表示考完第i场一共花了j的时间来复习,且挂了k科
此时有两种情况需要讨论:
一是
k
=
=
0
k==0
k==0,即
d
p
2
[
i
]
[
j
]
[
k
dp2[i][j][k
dp2[i][j][k]只能由
d
p
2
[
i
−
1
]
[
j
−
d
p
1
[
i
]
[
f
]
]
[
g
]
+
m
i
n
(
f
,
100
)
dp2[i-1][j-dp1[i][f]][g]+min(f,100)
dp2[i−1][j−dp1[i][f]][g]+min(f,100)转移而来,
f
f
f代表第i场的分数;
二是
k
!
=
0
k!=0
k!=0,此时根据f的大小有第i场及不及格两种情况,则
d
p
2
[
i
]
[
j
]
[
k
]
dp2[i][j][k]
dp2[i][j][k]由
d
p
2
[
i
−
1
]
[
j
−
d
p
1
[
i
]
[
f
]
]
[
k
−
(
f
<
60
)
]
+
m
i
n
(
f
,
100
)
dp2[i-1][j-dp1[i][f]][k-(f<60)]+min(f,100)
dp2[i−1][j−dp1[i][f]][k−(f<60)]+min(f,100)
此时可以看出上面将
m
a
x
u
p
maxup
maxup设为200的原因:将两本资料视为一本提升分数为100,花费天数为两者花费之和的资料
AcCode:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<thread>
#include<set>
//#define int long long
#define inf 0x3f3f3f3f
using namespace std;
inline int max(int a, int b) { return (a > b) ? a : b; }
inline int min(int a, int b) { return (a < b) ? a : b; }
inline int number(char c) { return c - '0'; }
const int N = 1e5 + 100;
const int M = 210;
struct node {
int cost, val;
string name;
}book[N];
int dp1[55][M];//第i场考试获得j分的最小天数
int dp2[55][510][5];//第i场考试复习j天包括这场一共挂了k次的最高分
string exams[55];
int maxup = 200;
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t; cin >> t;
while (t--) {
int n; cin >> n;
map<string, int> rmap;
for (int i = 1; i <= n; i++) {
cin >> exams[i];
rmap[exams[i]] = i;
dp1[i][0] = 0;
}
int m; cin >> m;
for (int i = 1; i <= m; i++) {
cin >> book[i].name >> book[i].val >> book[i].cost;
}
for (int i = 1; i <= n; i++) {
for (int j = maxup; j; j--) dp1[i][j] = inf;
dp1[i][0] = 0;
}
for (int i = 1; i <= m; i++) {
int id = rmap[book[i].name];
for (int j = maxup; j >= book[i].val; j--) {
dp1[id][j] = min(dp1[id][j], dp1[id][j - book[i].val] + book[i].cost);
}
}
int maxd, maxp; cin >> maxd >> maxp;
for (int i = 1; i <= n; i++) {//第几场
for (int g = 0; g <= maxp && g <= i; g++) {//挂科数
if (g == 0) {
for (int f = maxup; f >= 60; f--) {//分数
for (int j = maxd; j >= dp1[i][f]; j--) {//花费的时间
dp2[i][j][g] = max(dp2[i][j][g], dp2[i - 1][j - dp1[i][f]][g] + min(f, 100));
}
}
}
else {
for (int f = maxup; f >= 0; f--) {//分数
for (int j = maxd; j >= dp1[i][f]; j--) {//花费的时间
dp2[i][j][g] = max(dp2[i][j][g], dp2[i - 1][j - dp1[i][f]][g - (f < 60)] + min(f, 100));
}
}
}
}
}
int ans = 0;
for (int i = 1; i <= maxd; i++) {
for (int j = 0; j <= maxp; j++) {
ans = max(ans, dp2[n][i][j]);
}
}
if (ans >= (n - maxp) * 60)cout << ans << endl;
else cout << -1 << endl;
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= maxd; j++) {
for (int k = 0; k <= maxp; k++) {
dp2[i][j][k] = 0;
}
}
}
}
}