P12196 [NOISG 2025 Prelim] Lasers 2
EuphoricStar · · 题解
考虑将最终的局面划分成,若干个极长的,每一列都至少有一个滑动墙的列连续段。设划分出来的连续段是
-
- 令
x = \max\limits_{p = 1}^h r_p - l_p + 1 ,则\exists i \in [1, t], r_i - l_i + 1 \ge x ,因为要给最长的滑动墙留够位置放。
于是我们转而求满足条件的划分方案中,
- 第
i 位留空,有f_{i, j, k} \gets f_{i - 1, j - 1, k} ; - 第
i 位是一个连续段的右端点,枚举这个连续段的左端点l ,有f_{i, j, k \lor [i - l + 1 \ge x]} \gets f_{l - 1, j, k} + g(l, i) 。
朴素转移时间复杂度为
设
#include <bits/stdc++.h>
#define fst first
#define scd second
#define pb emplace_back
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<int, int> pii;
const int maxn = 2020;
ll n, m, K, f[maxn][maxn][2];
vector<pii> vc[maxn];
struct node {
ll l, r, x;
} a[maxn];
struct SGT {
ll a[maxn << 2], tag[maxn << 2];
inline void pushup(int x) {
a[x] = max(a[x << 1], a[x << 1 | 1]);
}
inline void pushtag(int x, ll y) {
a[x] += y;
tag[x] += y;
}
inline void pushdown(int x) {
if (!tag[x]) {
return;
}
pushtag(x << 1, tag[x]);
pushtag(x << 1 | 1, tag[x]);
tag[x] = 0;
}
void build(int rt, int l, int r) {
tag[rt] = 0;
a[rt] = -1e18;
if (l == r) {
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
}
void update(int rt, int l, int r, int ql, int qr, ll x) {
if (ql <= l && r <= qr) {
pushtag(rt, x);
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if (ql <= mid) {
update(rt << 1, l, mid, ql, qr, x);
}
if (qr > mid) {
update(rt << 1 | 1, mid + 1, r, ql, qr, x);
}
pushup(rt);
}
void modify(int rt, int l, int r, int x, ll y) {
if (l == r) {
a[rt] = y;
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
(x <= mid) ? modify(rt << 1, l, mid, x, y) : modify(rt << 1 | 1, mid + 1, r, x, y);
pushup(rt);
}
ll query(int rt, int l, int r, int ql, int qr) {
if (ql > qr) {
return -1e18;
}
if (ql <= l && r <= qr) {
return a[rt];
}
pushdown(rt);
int mid = (l + r) >> 1;
ll res = -1e18;
if (ql <= mid) {
res = max(res, query(rt << 1, l, mid, ql, qr));
}
if (qr > mid) {
res = max(res, query(rt << 1 | 1, mid + 1, r, ql, qr));
}
return res;
}
} T[2];
void solve() {
scanf("%lld%lld%lld", &n, &m, &K);
for (int i = 1; i <= n; ++i) {
scanf("%lld%lld%lld", &a[i].l, &a[i].r, &a[i].x);
vc[a[i].r].pb(a[i].l, a[i].x);
}
ll s = 0, mx = 0;
for (int i = 1; i <= n; ++i) {
s += a[i].x;
mx = max(mx, a[i].r - a[i].l + 1);
}
mems(f, -0x3f);
f[0][0][0] = 0;
for (int j = 0; j <= m; ++j) {
T[0].build(1, 1, m);
T[1].build(1, 1, m);
for (int i = 1; i <= m; ++i) {
for (int k = 0; k <= 1; ++k) {
if (j) {
f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][k]);
}
}
T[0].modify(1, 1, m, i, f[i - 1][j][0]);
T[1].modify(1, 1, m, i, f[i - 1][j][1]);
for (pii p : vc[i]) {
T[0].update(1, 1, m, 1, p.fst, p.scd);
T[1].update(1, 1, m, 1, p.fst, p.scd);
}
f[i][j][0] = max(f[i][j][0], T[0].a[1]);
f[i][j][1] = max({f[i][j][1], T[1].a[1], T[0].query(1, 1, m, 1, i - mx + 1)});
}
}
for (int i = m; ~i; --i) {
if (s - f[m][i][1] <= K) {
printf("%d\n", i);
return;
}
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}