2021HDU多校第二场 1008 I love exam 背包+DP
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021HDU多校第二场 1008 I love exam 背包+DP相关的知识,希望对你有一定的参考价值。
原题链接:https://acm.hdu.edu.cn/showproblem.php?pid=6968
题意
有n门课,m个学习资料,每个学习资料可以在bi天里提升ai的分数,每门课总分不能超过100分,同时可以挂p门课,学习总时长为t。问如何安排学习可以使得总分最大。
分析
题目相当绕,仔细分析一下,我们可以把每门课的学习资料先预处理出来,用 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示第i门课获得j分最少需要多少天。然后就可以开始快乐dp了。
我们设一个状态
f
[
i
]
[
j
]
[
k
]
[
o
]
f[i][j][k][o]
f[i][j][k][o]分别表示第i门课,当前已经学习了j天,当前这门课得分为k,当前已经挂了o门课,状态的转移非常好表示
f
[
i
]
[
j
]
[
k
]
[
o
]
=
m
a
x
(
f
[
i
−
1
]
[
j
−
d
p
[
i
]
[
k
]
]
[
k
p
r
e
]
[
o
]
+
k
(
不
挂
科
)
f[i][j][k][o]=max(f[i-1][j-dp[i][k]][k_{pre}][o]+k(不挂科)
f[i][j][k][o]=max(f[i−1][j−dp[i][k]][kpre][o]+k(不挂科)
f [ i ] [ j ] [ k ] [ o ] = m a x ( f [ i − 1 ] [ j − d p [ i ] [ k ] ] [ k p r e ] [ o − 1 ] + k ( 挂 科 ) f[i][j][k][o]=max(f[i-1][j-dp[i][k]][k_{pre}][o-1]+k(挂科) f[i][j][k][o]=max(f[i−1][j−dp[i][k]][kpre][o−1]+k(挂科)
如果直接枚举转移会超时,在记录一个 m x [ i ] [ j ] [ o ] mx[i][j][o] mx[i][j][o]代表前i门课第j天挂科o次的最大分数,这个记录了 k ∈ [ 0 , 100 ] k∈[0,100] k∈[0,100]之内的最值,因此转移的时候可以直接转移上一层的最大值,即
f [ i ] [ j ] [ k ] [ o ] = m x [ i − 1 ] [ j − d p [ i ] [ k ] ] [ o ] + k ( 不 挂 科 ) f[i][j][k][o]=mx[i-1][j-dp[i][k]][o]+k(不挂科) f[i][j][k][o]=mx[i−1][j−dp[i][k]][o]+k(不挂科)
f [ i ] [ j ] [ k ] [ o ] = m x [ i − 1 ] [ j − d p [ i ] [ k ] ] [ o − 1 ] + k ( 挂 科 ) f[i][j][k][o]=mx[i-1][j-dp[i][k]][o-1]+k(挂科) f[i][j][k][o]=mx[i−1][j−dp[i][k]][o−1]+k(挂科)
还有就是处理-1的情况,我们对所有门课 ∑ m i n d p [ i ] [ 60..100 ] > t \\sum mindp[i][60..100]>t ∑mindp[i][60..100]>t那么必定无解
赛中数组开小导致一直没过,调到自闭,我是演员
Code
#include <bits/stdc++.h>
#define lowbit(i) i & -i
#define Debug(x) cout << x << endl
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const ll INF = 1e18;
const int N = 3e5 + 10;
const int M = 1e6 + 10;
const int MOD = 998244353;
int dp[55][105];
int a[55][15005], b[55][15005];
int f[55][505][105][5], mx[55][505][5];
int num[55], t, p;
void solve() {
int T; cin >> T; while (T--) {
int n; cin >> n;
for (int i = 1; i <= n; i++) num[i] = 0;
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
memset(mx, -0x3f, sizeof mx);
memset(f, -0x3f, sizeof f);
map<string, int> mp;
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
mp[s] = i;
}
int m; cin >> m;
for (int i = 1; i <= m; i++) {
string s; cin >> s;
int x, y; cin >> x >> y;
a[mp[s]][++num[mp[s]]] = x;
b[mp[s]][num[mp[s]]] = y;
}
cin >> t >> p;
//p = min(n, p);
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; i++) {
dp[i][0] = 0;
for (int j = 1; j <= num[i]; j++) {
for (int k = 100; k >= a[i][j]; k--) {
dp[i][k] = min(dp[i][k], dp[i][k - a[i][j]] + b[i][j]);
}
}
}
vector<int> ve;
for (int i = 1; i <= n; i++) {
int Min = 1e9;
for (int j = 60; j <= 100; j++) {
Min = min(Min, dp[i][j]);
}
ve.push_back(Min);
}
sort(ve.begin(), ve.end());
int sum = 0;
for (int i = 0; i < min((int) ve.size(), n - p); i++) {
sum += ve[i];
}
if (sum > t) {
cout << -1 << endl;
continue;
}
//cout << dp[1][60] << endl;
int ans = 0;
f[0][0][0][0] = mx[0][0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= t; j++) {
for (int k = 0; k <= 100; k++) {
for (int o = 0; o <= p; o++) {
if (k >= 60) {
if (j >= dp[i][k]) {
f[i][j][k][o] = max(f[i][j][k][o], mx[i-1][j-dp[i][k]][o] + k);
}
} else {
if (j >= dp[i][k] && o) {
f[i][j][k][o] = max(f[i][j][k][o], mx[i-1][j-dp[i][k]][o-1] + k);
}
}
mx[i][j][o] = max(mx[i][j][o], f[i][j][k][o]);
ans = max(ans, f[i][j][k][o]);
}
}
}
}
cout << ans << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}
以上是关于2021HDU多校第二场 1008 I love exam 背包+DP的主要内容,如果未能解决你的问题,请参考以下文章
2019年杭电多校第二场 1008题Harmonious Army(HDU6598+最小割+建图)
hdu_6047: Maximum Sequence (2017 多校第二场 1003)贪心