题目链接:P1833 樱花
思路: 显然将时间看作容量, C i C_i Ci看作价值, T i T_i Ti看作大小, P i P_i Pi看作个数( P i = 0 P_i=0 Pi=0可以取无限个,视作完全背包),可以转化成混合背包求解。
令 T = T 2 − T 1 T=T_2-T_1 T=T2−T1,分开处理:
当 P i = 0 P_i=0 Pi=0或 P i × T i ≤ T P_i\times T_i\leq T Pi×Ti≤T(可以随便取而不会个数不够)时看作完全背包
其他情况下当作多重背包,数据量比较小可以用二进制优化转01背包 O ( T Σ log P i ) O(T\Sigma \log P_i) O(TΣlogPi)或者单调队列 O ( T N ) O(TN) O(TN)。
代码:
这里提供一种单调队列优化的写法。
#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
#include <set>
#include <map>
#include <stack>
#include <iomanip>
#include <numeric>
#include <cmath>
#include <functional>
#include <numeric>
#include <ctime>
#include <random>
#include <queue>
#include <vector>
#include <unordered_map>
#define sqr(x) ((x) * (x))
#define fo(x) for(int i=0;i<x;i++)
#define _for(a,b,c) for(int a=b;a<c;a++)
#define _rep(a,b,c) for(int a=b;a<=c;a++)
#define ll long long
#define inf 0x3f3f3f3f
#define endl '\n'
#define ull unsigned long long
#define int long long
#define MAXN 1000005
#define MAXM 26
#define mod 998244353
using namespace std;
int dp[1005];
int mp[1005];
int q[1005];
void solve() {
int h1, m1, h2, m2;
char c;
int n;
cin >> h1 >> c >> m1;
cin >> h2 >> c >> m2;
int V = (h2 - h1) * 60 + m2 - m1;
cin >> n;
fo(n) {
int w, v, s;
cin >> v >> w >> s;
if (s == 0 || s * v >= V) {
for (int i = v; i <= V; i++) {
dp[i] = max(dp[i], dp[i - v] + w);
}
}
else {
for (int ind = 0; ind < v; ind++) {
int head = 0, tail = 0;
for (int i = ind; i <= V; i += v) {
int temp = dp[i] - i / v * w;
while (head < tail && q[tail - 1] <= temp) {
tail--;
}
if (mp[head] < i - s * v) {
head++;
}
mp[tail] = i;
q[tail++] = temp;
dp[i] = q[head] + i / v * w;
}
}
}
}
cout << dp[V] << endl;
}
signed main() {
cin.tie(nullptr)->sync_with_stdio(0);
int t = 1;
//cin >> t;
while (t--) {
solve();
}
}