[NOIP2023] 天天爱打卡 题解

· · 题解

l_i=x_i-y_i+1,r_i=x_i

f_{i,0/1} 表示前 i 天中第 i 天不跑/跑时的最大收益。有转移方程:

对于 $f_{i,1}$ 的转移,为方便,我们可以将在转移 $f_{j,0}$ 的时候就将 $dj$ 加入其中,而对于 $\sum\limits_{j<l_u\le r_u\le i}v_u$,我们可以在转移前将所有满足 $r_u=i$ 的 $(l_u,r_u,v_u)$ 的贡献加入 $f_{j,0}$(即对所有 $j<l_u$ 的 $f_{j,0}$ 加上 $v_u$)。于是 $f_{i,1}$ 的转移就变成了简单的区间 $\max$,使用线段树维护 $f_{j,0}$ 即可,时间复杂度 $\mathcal{O}(n\log n)$,考虑优化。 注意到最终答案中我们必然只在形如 $[r_i+1,l_j-1]$ 的区间中不跑,且只在形如 $[l_i,r_j]$ 的区间中跑,因此决策点只可能是所有 $l_j-1$ 和 $r_j$,对所有 $l_i-1$ 和 $r_i$ 离散化,并只考虑这 $\mathcal{O}(m)$ 个位置即可。时间复杂度 $\mathcal{O}(m\log m)$。 ```cpp #include <algorithm> #include <iostream> using namespace std; using LL = long long; const int kM = 1e5 + 1, kN = kM * 2; struct C { int l, r, v; bool operator<(const C &o) const { return r < o.r; } } a[kM]; struct E { LL mx, ta; } e[kN << 2]; int cid, tt; int n, m, k, v, b[kN]; LL d, f[kN]; void Pu(int x) { e[x].mx = max(e[x * 2].mx, e[x * 2 + 1].mx); } void Pa(int x, LL v) { e[x].mx += v, e[x].ta += v; } void Pd(int x) { Pa(x * 2, e[x].ta), Pa(x * 2 + 1, e[x].ta), e[x].ta = 0; } void B(int x, int l, int r) { e[x].ta = 0; if (l == r) { e[x].mx = (l ? -1e18 : 0); return; } int m = l + r >> 1; B(x * 2, l, m), B(x * 2 + 1, m + 1, r); Pu(x); } void U(int x, int l, int r, int t, LL v) { if (l == r) { e[x].mx = v; return; } Pd(x); int m = l + r >> 1; if (t <= m) { U(x * 2, l, m, t, v); } else { U(x * 2 + 1, m + 1, r, t, v); } Pu(x); } void A(int x, int l, int r, int tl, int tr, LL v) { if (l == tl && r == tr) { Pa(x, v); return; } Pd(x); int m = l + r >> 1; if (tl <= m) { A(x * 2, l, m, tl, min(m, tr), v); } if (m < tr) { A(x * 2 + 1, m + 1, r, max(m + 1, tl), tr, v); } Pu(x); } LL Q(int x, int l, int r, int tl, int tr) { if (l == tl && r == tr) { return e[x].mx; } Pd(x); int m = l + r >> 1; LL s = -1e18; if (tl <= m) { s = max(s, Q(x * 2, l, m, tl, min(m, tr))); } if (m < tr) { s = max(s, Q(x * 2 + 1, m + 1, r, max(m + 1, tl), tr)); } return s; } int main() { ios::sync_with_stdio(0), cin.tie(0); for (cin >> cid >> tt; tt--;) { cin >> n >> m >> k >> d; v = 0; for (int i = 1; i <= m; ++i) { cin >> a[i].r >> a[i].l >> a[i].v; a[i].l = a[i].r - a[i].l; b[++v] = a[i].l, b[++v] = a[i].r; } sort(b + 1, b + v + 1); v = unique(b + 1, b + v + 1) - b - 1; for (int i = 1; i <= m; ++i) { a[i].l = lower_bound(b + 1, b + v + 1, a[i].l) - b; a[i].r = lower_bound(b + 1, b + v + 1, a[i].r) - b; } sort(a + 1, a + m + 1); B(1, 0, v); LL pm = 0; for (int i = 1, j = 1, u = 0; i <= v; ++i) { U(1, 0, v, i, pm + d * b[i]); for (; j <= m && a[j].r == i; ++j) { A(1, 0, v, 0, a[j].l, a[j].v); } for (; u < i && b[u] < b[i] - k; ++u) { } if (u < i) { f[i] = Q(1, 0, v, u, i - 1) - d * b[i]; } else { f[i] = -1e18; } pm = max(pm, f[i]); } cout << pm << '\n'; } return 0; } ```