CF1650F Vitaly and Advanced Useless Algorithms
CF1650F
原题链接 ←Click it
题目大意:有\(n\)个课程,每个课程的截止时间是\(a_i(a_i < a_i < a_2 <...< a_n)\),要求在在规定时间内完成课程。现在有\(m\)个方案,每个方案表示对第\(i\)个课程学习\(t\)时间,增加完成度\(p\),要求方案能重复选择。如可以完成,则输出方案的个数,以及选择的方案,要求时间最短;如不能按时完成,则输出\(-1\)。
解题思路:考虑每个课程都是一个小的背包问题,对每个课程分开求解,如果可以完成,则利用dp数组反推出是由哪些方案转移过来的。
参考代码:
void solve() {
int n, m;
cin >> n >> m;
vector<int> a(n);
vector<int> res;
for(int i = 0; i < n; i ++) {
cin >> a[i];
}
struct node {
int t, p, idx;
};
vector<vector<node>> op(n);
for(int i = 0; i < m; i ++) {
int e, p, t;
cin >> e >> t >> p;
e --;
op[e].push_back({t, p, i + 1});
}
int tm = 0;
for(int i = 0; i < n; i ++) {
int N = op[i].size();
vector<vector<int>> dp(N + 1, vector<int> (101, 1e9 + 1));
dp[0][0] = 0;
for(int j = 0; j < N; j ++) {
dp[j + 1] = dp[j];
for(int k = 0; k <= 100; k ++) {
int ed = min(100, k + op[i][j].p);
dp[j + 1][ed] = min(dp[j + 1][ed], dp[j][k] + op[i][j].t);
}
}
tm += dp[N][100];
if(tm > a[i]) {
cout << "-1\n";
return ;
}
int now = 100;
for(int j = N -1 ; j >= 0; j --) {
if(dp[j + 1][now] == dp[j][now]) {
continue;
}
res.push_back(op[i][j].idx);
for(int f = 0; f <= now; f ++) {
int t = min(100, f + op[i][j].p);
if(now == t && dp[j][f] + op[i][j].t == dp[j + 1][t]) {
now = f;
break;
}
}
}
}
cout << res.size() << '\n';
for(auto x : res) {
cout << x << ' ';
}
cout << '\n';
}