题目描述

在比特镇一共有 \(n\) 家商店,编号依次为 \(1\)\(n\)
每家商店只会卖一种物品,其中第 \(i\) 家商店的物品单价为 \(c_i\),价值为 \(v_i\),且该商店开张的时间为 \(t_i\)
\(Byteasar\) 计划进行 \(m\) 次购物,其中第 \(i\) 次购物的时间为 \(T_i\),预算为 \(M_i\)
每次购物的时候,\(Byteasar\) 会在每家商店购买最多一件物品,当然他也可以选择什么都不买
如果购物的时间早于商店开张的时间, 那么显然他无法在这家商店进行购物。
现在 \(Byteasar\) 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助 \(Byteasar\) 合理安排购物计划。
注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用。
对于 \(100\%\) 的数据:
    \(n \leq 300, m \leq 100000\)
    \(c_i \ leq 10^9, M_i \leq 10^9, v_i \leq 300, t_i \leq 300,T_i \leq 300\)

题解

显然因为\(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\n", qans[i]);
    return 0;
}
12-30 09:41