背包。
首先考虑将所有询问离线按照$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; }