题目描述
在比特镇一共有 (n) 家商店,编号依次为 (1) 到 (n)。
每家商店只会卖一种物品,其中第 (i) 家商店的物品单价为 (c_i),价值为 (v_i),且该商店开张的时间为 (t_i)。
(Byteasar) 计划进行 (m) 次购物,其中第 (i) 次购物的时间为 (T_i),预算为 (M_i)
每次购物的时候,(Byteasar) 会在每家商店购买最多一件物品,当然他也可以选择什么都不买
如果购物的时间早于商店开张的时间, 那么显然他无法在这家商店进行购物。
现在 (Byteasar) 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助 (Byteasar) 合理安排购物计划。
注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用。
对于 (100\%) 的数据:
(n, m in [1,300]; c_i,M_i in [1, 10^9]; vi,t_i,Ti in [1,300])
观察数据发现不用开long long。
题解
显然因为(c_i,M_i leq 10^9),不可能去做01背包。
那么我们离线排序处理询问,并按照时间递增的顺序DP。
每次对于一个物品,我们"倒做"01背包,即计算某个价值所需要的最小代价。
分析
考场一阵乱打,空间开小,(20)pts 滚粗。
后来还莫名奇妙的多动规了一次,导致变为 (80)pts 。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
struct Mark{
int c, v, t;
bool operator < (const Mark &rhs) const {
return t < rhs.t;
}
} market[305];
struct Qry{
int t, m, id;
bool operator < (const Qry &rhs) const {
return t < rhs.t;
}
} qry[100005];
int g[90005];
int qans[100005];
inline void flush(int u){
for (int i = 90000; i >= market[u].c; --i){
if (g[i] > g[i - market[u].c] + market[u].v)
g[i] = g[i - market[u].c] + market[u].v;
}
for (int i = 90000; i >= 1; --i)
if (g[i] > g[i + 1]) g[i] = g[i + 1];
}
int main(){
int n, m; scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d %d %d", &market[i].v, &market[i].c, &market[i].t);
sort(market + 1, market + n + 1);
for (int i = 1; i <= m; ++i){
int t, m; scanf("%d %d", &t, &m);
qry[i] = {t, m, i};
}
sort(qry + 1, qry + m + 1);
for (int i = 1; i <= 90004; ++i) g[i] = 1000000007;
for (int i = 1, pos = 1; i <= m; ++i){
for ( ; market[pos].t <= qry[i].t && pos <= n; ++pos)
flush(pos);
qans[qry[i].id] = upper_bound(g, g + 90001, qry[i].m) - g - 1;
}
for (int i = 1; i <= m; ++i)
printf("%d
", qans[i]);
return 0;
}