Luogu 3537 [POI2012]SZA-Cloakroom

背包。

首先考虑将所有询问离线按照$m$从小到大排序,然后把所有物品按照$a$从小到大排序,对于每一个询问不断加入物品。

设$f_i$表示在组成容量为$i$的背包的所有方案中$b$最小的一个物品的最大$b$是多少,对于物品$i$和容量$j$,有转移$f_j = max(f_j, min(f_{j - c_i}, b_i))$。

时间复杂度$O(MaxK * n)$,感觉非常紧,实际上还行。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1005;
const int M = 1e6 + 5;
const int Maxm = 1e5;
const int inf = 1 << 30;

int n, qn, f[Maxm + 5];
bool ans[M];

struct Item {
    int sa, sb, sc;
    
    friend bool operator < (const Item &x, const Item &y) {
        return x.sa < y.sa;
    }
    
} a[N];

struct Querys {
    int m, k, s, id;
    
    friend bool operator < (const Querys &x, const Querys &y) {
        return x.m < y.m;    
    }
    
} q[M];

inline void read(int &X) {
    X = 0; char ch = 0; int op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline int min(int x, int y) {
    return x > y ? y : x;
}

inline void chkMax(int &x, int y) {
    if(y > x) x = y;
}

int main() {
    read(n);
    for(int i = 1; i <= n; i++) 
        read(a[i].sc), read(a[i].sa), read(a[i].sb);
    read(qn);
    for(int i = 1; i <= qn; i++) {
        read(q[i].m), read(q[i].k), read(q[i].s);
        q[i].id = i;
    }
    
    sort(a + 1, a + 1 + n), sort(q + 1, q + 1 + qn);
    f[0] = inf;
    for(int j = 1, i = 1; i <= qn; i++) {
        for(; j <= n && a[j].sa <= q[i].m; ++j) {
            for(int k = Maxm; k >= a[j].sc; k--)
                chkMax(f[k], min(f[k - a[j].sc], a[j].sb));
        }
        if(f[q[i].k] > q[i].m + q[i].s) ans[q[i].id] = 1;
    }
    
    for(int i = 1; i <= qn; i++)
        puts(ans[i] ? "TAK" : "NIE");
    
    return 0;
}  
View Code

猜你喜欢

转载自www.cnblogs.com/CzxingcHen/p/9896045.html