题目
https://www.lydsy.com/JudgeOnline/problem.php?id=3163
题解
做一个前缀背包,后缀背包,询问时候合并一下。。
话说预处理背包的部分用 log 拆分 跑得比单调队列还快好气呀。。。
#include <bits/stdc++.h>
using namespace std;
#define getchar getchar_unlocked
#define rep(i, n) for (int i = 0; i < n; ++i)
int get() {
int n;
char c;
while ((c = getchar()) < '0');
n = c - '0';
while ((c = getchar()) >= '0') n = n * 10 + c - '0';
return n;
}
int dpA[1010][1010], dpB[1010][1010];
int W[1010], V[1010], S[1010];
pair<int, int> deq[1010];
void solve() {
int N;
scanf("%d", &N);
for (int i = 1; i <= N; ++i) {
W[i] = get();
V[i] = get();
S[i] = get();
}
rep(i, N) {
int* curr = dpA[i];
int* next = dpA[i + 1];
int w = W[i + 1], v = V[i + 1], s = S[i + 1];
rep(q, w) {
int b = (1000 - q) / w;
int qh = 0, qt = 0;
int ww = q - w, vv = -v;
rep(j, b + 1) {
ww += w;
vv += v;
int nd = curr[ww] - vv;
while (qh != qt && nd >= deq[qt - 1].first) --qt;
deq[qt++] = make_pair(nd, j);
if (deq[qh].second == j - s - 1) ++qh;
next[ww] = deq[qh].first + vv;
}
}
}
for (int i = N + 1; i >= 2; --i) {
int* curr = dpB[i];
int* next = dpB[i - 1];
int w = W[i - 1], v = V[i - 1], s = S[i - 1];
rep(q, w) {
int b = (1000 - q) / w;
int qh = 0, qt = 0;
int ww = q - w, vv = -v;
rep(j, b + 1) {
ww += w;
vv += v;
int nd = curr[ww] - vv;
while (qh != qt && nd >= deq[qt - 1].first) --qt;
deq[qt++] = make_pair(nd, j);
if (deq[qh].second == j - s - 1) ++qh;
next[ww] = deq[qh].first + vv;
}
}
}
int Q;
scanf("%d", &Q);
rep(_, Q) {
int id, w;
scanf("%d %d", &id, &w);
++id;
if (id == 1) {
printf("%d\n", dpB[2][w]);
} else if (id == N) {
printf("%d\n", dpA[N - 1][w]);
} else {
int ma = 0;
int* p = dpA[id - 1], *s = dpB[id + 1];
for (int j = 0; j <= w; ++j) {
ma = max(ma, p[j] + s[w - j]);
}
printf("%d\n", ma);
}
}
}
int main() {
solve();
return 0;
}