【洛谷 P1833 樱花】解题报告(多重背包)
作者:互联网
题意简述
\(n\) 种物品,每种物品有代价 \(T_i\)、权值 \(C_i\) 和个数 \(A_i\)(若 \(A_i=0\) 表示有无穷多个),最多代价为 \(m\),权值和最大为多少。
\(1\le m\le 10^3\),\(1\le n\le 10^4\)。
题解
首先,时间 HH1:MM1~HH2:MM2
的跨度非常好算,这里就不说了,假设为 \(m\)。
由于 \(m\le 10^3\) 且 \(T_i > 0\),显然每种物品不可能被选择超过 \(10^3\) 次,因此如果 \(A_i=0\) 可以直接赋值 \(A_i\gets 10^3\),同时对于所有 \(A_i\) 进行 \(A_i\gets\min\{A_i,10^3\}\)。
然后本题转化为多重背包问题,直接二进制拆分后跑 0/1 背包即可。
参考代码
//By: Luogu@rui_er(122461)
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
using namespace std;
typedef long long ll;
const int N = 2e5+5, M = 1005, inf = 1000;
int HH1, MM1, HH2, MM2, n, m, a[N], b[N], c[N], cost[N], v[N], tot, dp[M];
template<typename T> void chkmin(T &x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T &x, T y) {if(x < y) x = y;}
int main() {
scanf("%d:%d %d:%d %d", &HH1, &MM1, &HH2, &MM2, &n);
m = (HH2 - HH1) * 60 + MM2 - MM1;
rep(i, 1, n) {
scanf("%d%d%d", &a[i], &b[i], &c[i]);
if(!c[i]) c[i] = inf;
chkmin(c[i], inf);
rep(j, 0, 10) {
if(c[i] < (1 << j)) break;
cost[++tot] = a[i] * (1 << j);
v[tot] = b[i] * (1 << j);
c[i] -= 1 << j;
}
if(c[i]) {
cost[++tot] = a[i] * c[i];
v[tot] = b[i] * c[i];
}
}
// rep(i, 1, tot) printf("%d %d\n", cost[i], v[i]);
rep(i, 1, tot) per(j, m, cost[i]) chkmax(dp[j], dp[j-cost[i]]+v[i]);
printf("%d\n", dp[m]);
return 0;
}
标签:__,10,le,洛谷,HH2,MM1,MM2,P1833,解题 来源: https://www.cnblogs.com/ruierqwq/p/LG-P1833.html