题解:P17140 [NOI 2026] 线段
WorldMachine · · 题解
直接做。这样设状态可能舒服点。
区间图是弦图,没有环等价于没有三元环,也就是说每个坐标至多被覆盖
先把线段按照左端点升序排序(相等时按照右端点升序排序),然后逐个加入,假设当前最大和次大的右端点分别为
因此设
注意为了避免算重,求出来合法
#include <bits/stdc++.h>
#include "segment.h"
using namespace std;
const int P = 998244353;
struct range { int l, r, i; };
inline void add(int &x, int y) { (x += y) >= P && (x -= P); }
void init(int c, int t) {}
vector<int> segment(int n, int m, int k, vector<int> l, vector<int> r) {
vector<range> a;
for (int i = 0; i < n; i++) a.push_back({l[i], r[i], i});
sort(a.begin(), a.end(), [](const range &x, const range &y) { return x.l == y.l ? x.r < y.r : x.l < y.l; });
vector<int> pt(m + 1, n);
for (int i = 0; i <= m; i++) for (int j = i ? pt[i - 1] : 0; j < n; j++)
if (a[j].l > i) { pt[i] = j; break; }
vector<vector<int> > f(m + 1, vector<int>(n)), d(m + 1, vector<int>(n + 1));
vector<int> ans(k + 1);
fill(f[0].begin(), f[0].end(), 1), ans[1] = n;
for (int s = 1; s < k; s++) {
for (int i = 0; i <= m; i++) fill(d[i].begin(), d[i].end(), 0);
for (int i = 0; i <= m; i++) for (int j = 0; j < n; j++) if (f[i][j]) {
auto [mn, mx] = minmax(a[j].r, i);
int l = max(pt[mn], j + 1), r = pt[mx] - 1;
if (l <= r) add(d[mx][l], f[i][j]), add(d[mx][r + 1], P - f[i][j]);
}
for (int i = 0; i <= m; i++) for (int j = 0, c = 0; j < n; j++)
add(c, d[i][j]), f[i][j] = c, add(ans[s + 1], c);
}
return ans;
}