题解:P17859 「GLR-R5」白露 / ros
P2441M
·
2026-11-08 19:31:24
·
题解
做死我了。
考虑每次往序列末尾添加一个数 x ,那么 x 是合法的当且仅当所有前面出现的 >x 的数都与 x 相邻。
设 L_x 表示 <x 的与 x 相邻的数构成的集合,R_x 表示 >x 的与 x 相邻的数构成的集合。
不妨先考虑记录最大值 v :令 f_v 表示最大值为 v 的合法序列个数。考虑添加一个数 x 后,如何得到最大值为 v 的合法序列。若添加的是 v ,则贡献显然是 \sum\limits_{i=1}^vf_i ;否则若添加的是 x\in L_v ,则原序列最大值为 v ,但是这里只保证 x\in L_v 不足以保证 x 合法。
这启发我们再去记录 g_{v,x} 表示最大值为 v 、x 可以添加到序列末尾的序列个数。由于 x\in L_v ,所以状态个数显然是 \mathcal{O}(n) 级别的。
这样很容易就能得到 f 的转移:
f'_v=\sum_{i=1}^vf_i+\sum_{x\in L_v}g_{v,x}
再来考虑 g 的转移。若原序列最大值为 v ,则添加 v 或者 x 显然都不影响 x 的合法性。若添加满足 x<t<u 的数 t ,则 x,t 都与 u 相邻,加入 t 后 x 必然不合法。若添加满足 t<x 的数 t ,那么我们保证 t 可以被添加到末尾即可。
但是这里又出现了新的需要记录合法性的量。那咋办?
考虑先计算出 \sum\limits_{t<x\land t\in L_v}g_{v,t} ,但是这样会多算 x 不能添加到末尾的序列。
做一个重要的观察:若 x\in L_v 且 x 不能添加到末尾,则 <x 的可以被添加到末尾的数至多只有一个。这是因为,考虑 x 不合法说明存在 x<y<v 使得 x,y 不相邻,那么 <x 的合法的数必须同时与 y,v 相邻,显然至多只有一个。
这启发我们再去记录 h_{v,x} 表示最大值为 v 、x 不能添加到序列末尾,但存在 t<x 能添加到序列末尾的序列个数。
这样我们直接减去 h_{v,x} 就能扣掉多算的部分了。原序列最大值为 v 的贡献就是 2g_{v,x}+\sum\limits_{t<x\land t\in L_v}g_{v,t}-h_{v,x} 。
再来考虑原序列最大值为 u<v 的情况。此时我们保证 x 在原序列中合法即可。显然 u\leq x 的序列必然合法,而若 x<u<v 则要有 u\in R_x ,贡献 g_{u,x} 。
这样我们就得到了 g 的完整转移
g'_{v,x}=2g_{v,x}+\sum_{t<x\land t\in L_v}g_{v,t}-h_{v,x}+\sum_{u=1}^xf_u+\sum_{u\in R_x\land u<v}g_{u,x}
再来考虑 h 的转移。还是先考虑原序列最大值为 v 的情况。添加 v,t 都是合法的,若添加一个满足 x<p<v 的数 p 显然会使 t 变得不合法。而若原本 x 合法,则为了让它变得不合法必然会令 t<x 也变得不合法。因此贡献恰好就是 2h_{v,x} 。
再来考虑原序列最大值为 u<v 的情况。显然要有 u>x ,否则 x 不可能变得不合法,同时 t 要在原序列中合法。由此得到 h 的完整转移:
h'_{v,x}=2h_{v,x}+\sum_{t\in L_v\land t<x}\sum_{u\in R_t\land x<u<v}g_{u,t}
至此我们终于得到了所有 DP 转移。
暴力做上述转移的时间复杂度为 \mathcal{O}(n^2m) ,需要优化。
考虑 $h$ 的转移如何优化。观察到 $v,t$ 相邻且 $L_v,R_t$ 分别是 $\mathcal{O}(deg_v),\mathcal{O}(deg_t)$ 量级的。考虑固定 $v,t$,把转移重写成:枚举 $u\in R_t\land u<v$,再枚举 $x\in L_v\land t<x<u$,令 $h'_{v,x}\gets h'_{v,x}+g_{u,t}$。我们只要把转移做到 $\mathcal{O}(\min(deg_v,deg_t))$ 的复杂度总体就是 $\mathcal{O}(n)$ 的了。
若枚举 $u$,则相当于在 $L_v$ 的一个区间上的 $h$ 做区间加;若枚举 $x$,则相当于在 $R_t$ 的一个区间上求 $g$ 的区间和。取较小的的一侧做即可。
这样我们就把时间复杂度做到 $\mathcal{O}(nm+n\log{n})$。
大抵不是预期做法,所以非常卡常。需要把大部分 `vector` 改成 CSR 才能卡过去。
:::success[主要代码]
```cpp
int tc, n, m, posL[MAXN], posR[MAXN];
int degL[MAXN], stL[MAXN], edL[MAXN];
int degR[MAXN], stR[MAXN], edR[MAXN];
pii edges[MAXN];
vector<int> pos[MAXN];
pii L[MAXN], R[MAXN];
mint df[MAXN], sum[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> tc;
while (tc--) {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
pos[i].clear();
degL[i] = degR[i] = 0;
}
for (int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
if (u > v) swap(u, v);
edges[i] = {u, v};
++degL[v];
++degR[u];
}
stL[1] = edL[1] = stR[1] = edR[1] = 0;
for (int i = 1; i < n; ++i) {
stL[i + 1] = edL[i + 1] = stL[i] + degL[i];
stR[i + 1] = edR[i + 1] = stR[i] + degR[i];
}
for (int i = 1; i < n; ++i) {
auto [u, v] = edges[i];
L[edL[v]++] = {u, i};
R[edR[u]++] = {v, i};
}
for (int u = 1; u <= n; ++u) {
sort(L + stL[u], L + edL[u]);
sort(R + stR[u], R + edR[u]);
}
for (int i = 1; i < n; ++i) {
auto [u, v] = edges[i];
posR[i] = lower_bound(R + stR[u], R + edR[u], pii{v, 0}) - R - stR[u];
posL[i] = lower_bound(L + stL[v], L + edL[v], pii{u, 0}) - L - stL[v];
if (edR[u] - stR[u] <= edL[v] - stL[v]) {
pos[i].reserve(posR[i]);
for (int p = 0; p < posR[i]; ++p) {
auto [x, id] = R[stR[u] + p];
pos[i].emplace_back(lower_bound(L + stL[v], L + edL[v], pii{x, 0}) - L - stL[v]);
}
} else {
pos[i].reserve(edL[v] - stL[v] - posL[i] - 1);
for (int p = posL[i] + 1; p < edL[v] - stL[v]; ++p) {
auto [x, id] = L[stL[v] + p];
pos[i].emplace_back(lower_bound(R + stR[u], R + edR[u], pii{x, 0}) - R - stR[u]);
}
}
}
vector<mint> f(n + 1, 1), g(n, 1), h(n, 0), ng(n), nh(n), preF(n + 1);
for (int len = 1; len <= m; ++len) {
for (int i = 1; i <= n; ++i) preF[i] = preF[i - 1] + f[i];
cout << preF[n] << " \n"[len == m];
if (len == m) break;
ranges::fill(ng, 0);
ranges::fill(nh, 0);
fill(df, df + edL[n], 0);
for (int u = 1; u <= n; ++u) {
mint pre = 0;
for (int _ = stL[u]; _ < edL[u]; ++_) {
auto [x, id] = L[_];
ng[id] += pre;
pre += g[id];
}
f[u] = preF[u] + pre;
sum[stR[u]] = 0;
for (int i = 0; i < edR[u] - stR[u]; ++i) {
ng[R[stR[u] + i].second] += sum[stR[u] + i];
if (i + 1 < edR[u] - stR[u]) sum[stR[u] + i + 1] = sum[stR[u] + i] + g[R[stR[u] + i].second];
}
}
for (int i = 1; i < n; ++i) {
auto [x, v] = edges[i];
ng[i] += g[i] * 2 - h[i] + preF[x];
nh[i] += h[i] * 2;
if (edR[x] - stR[x] <= edL[v] - stL[v]) {
int j = 0;
for (int p = 0; p < posR[i]; ++p) {
auto [y, id] = R[stR[x] + p];
if (posL[i] + 1 < edL[v] - stL[v]) df[stL[v] + posL[i] + 1] += g[id];
if (pos[i][j] < edL[v] - stL[v]) df[stL[v] + pos[i][j++]] -= g[id];
}
} else {
int j = 0;
for (int p = posL[i] + 1; p < edL[v] - stL[v]; ++p) {
auto [u, id] = L[stL[v] + p];
nh[id] += sum[stR[x] + posR[i]] - sum[stR[x] + pos[i][j++]];
}
}
}
for (int u = 1; u <= n; ++u) {
for (int i = 0; i < edL[u] - stL[u]; ++i) {
if (i) df[stL[u] + i] += df[stL[u] + i - 1];
nh[L[stL[u] + i].second] += df[stL[u] + i];
}
}
ng.swap(g);
nh.swap(h);
}
}
return 0;
}
```
:::