ABC262Ex Max Limited Sequence 题解
题意:
给定
同 P4229,但数据更强,目测只允许
考虑将条件 2 中每个限制拆分为:
即任意位置
对位置离散化后,利用线段树及标记永久化进行简单的区间取
综上所述,我们可以对
此处细节:
- 如果有
个位置不被任何限制覆盖,这些位置方案数为 。 - 如果一个限制
满足 ,则总方案数为 。线段树维护 区间最大值即可。
将所有
现在考虑如何在
给定
个限制 及 ,求满足以下条件的序列个数:
不妨设
显然如果第
如果第
如果不取,考虑若存在部分区间最后一个覆盖的位置为
综上所述,
此处细节:
- 需取模,计算可能出现负数。
- 离散化后序列相邻两项在原序列不一定连续。
目标:
#include <bits/stdc++.h>
#define maxm 400005
#define inf 0x3f3f3f3f
#define ad(i, j) i = (i % mod + j % mod + mod) % mod
#define mu(i, j) i = (i * j) % mod
#define ls(p) (p << 1)
#define rs(p) ((p << 1) + 1)
using namespace std;
const int mod = 998244353;
int n, m, k, num, nx, nf, b[maxm], bx[maxm];
int c[maxm];
struct Query {
int l, r, x;
} a[maxm];
vector<int> q[maxm], v[maxm];
inline bool cmp(int i, int j) { return a[i].r == a[j].r ? a[i].l > a[j].l : a[i].r < a[j].r; }
long long ans, f[maxm], g[maxm];
// Basic
inline int len(int x) { return (x & 1) ? (b[(x >> 1) + 1] - b[x >> 1] - 1) : 1; }
inline int qpow(int x, int p) {
if (!p) return 1;
long long tx = qpow(x, p >> 1);
return (p & 1) ? (tx * tx % mod * x % mod) : (tx * tx % mod);
}
// BIT
namespace Seg {
struct SegTree {
long long sum, mul, cov;
} t[maxm * 4];
void build(int p, int l, int r) {
t[p] = {g[l], 1, -1};
if (l < r) {
int mid = (l + r) >> 1;
build(ls(p), l, mid), build(rs(p), mid + 1, r);
t[p].sum = (t[ls(p)].sum + t[rs(p)].sum) % mod;
}
}
inline void spread(int p) {
if (~t[p].cov) {
t[ls(p)].sum = t[ls(p)].cov = t[rs(p)].sum = t[rs(p)].cov = t[p].cov;
t[ls(p)].mul = t[rs(p)].mul = 1;
t[p].cov = -1;
}
if (t[p].mul > 1) {
mu(t[ls(p)].sum, t[p].mul), mu(t[rs(p)].sum, t[p].mul);
mu(t[ls(p)].mul, t[p].mul), mu(t[rs(p)].mul, t[p].mul);
t[p].mul = 1;
}
}
void change(int p, int pl, int pr, int l, int r, int x, int tg = 0) {
if (l > r) return;
if (pl >= l && pr <= r) {
if (tg) t[p].mul = 1, t[p].sum = t[p].cov = x;
else mu(t[p].mul, x), mu(t[p].sum, x);
} else {
spread(p);
int mid = (pl + pr) >> 1;
if (l <= mid) change(ls(p), pl, mid, l, r, x, tg);
if (r > mid) change(rs(p), mid + 1, pr, l, r, x, tg);
t[p].sum = (t[ls(p)].sum + t[rs(p)].sum) % mod;
}
}
long long ask(int p, int pl, int pr, int l, int r) {
if (l > r) return 0;
else if (pl >= l && pr <= r) return t[p].sum;
spread(p);
int mid = (pl + pr) >> 1;
long long ans = 0;
if (l <= mid) ad(ans, ask(ls(p), pl, mid, l, r));
if (r > mid) ad(ans, ask(rs(p), mid + 1, pr, l, r));
return ans;
}
};
namespace Mn {
int ma[maxm * 4], tg[maxm * 4];
inline void init() { memset(tg, 0x3f, sizeof(tg)); }
void cover(int p, int pl, int pr, int l, int r, int x) {
if (pl >= l && pr <= r) tg[p] = min(tg[p], x);
else {
int mid = (pl + pr) >> 1;
if (l <= mid) cover(ls(p), pl, mid, l, r, x);
if (r > mid) cover(rs(p), mid + 1, pr, l, r, x);
}
}
void dfs(int p, int l, int r, int x) {
int mid = (l + r) >> 1;
x = min(x, tg[p]);
if (l == r) c[l] = x, ma[p] = len(l) ? x : 0;
else dfs(ls(p), l, mid, x), dfs(rs(p), mid + 1, r, x), ma[p] = max(ma[ls(p)], ma[rs(p)]);
}
int ask(int p, int pl, int pr, int l, int r) {
if (pl >= l && pr <= r) return ma[p];
int mid = (pl + pr) >> 1, ans = 0;
if (l <= mid) ans = max(ans, ask(ls(p), pl, mid, l, r));
if (r > mid) ans = max(ans, ask(rs(p), mid + 1, pr, l, r));
return ans;
}
};
signed main() {
ans = 1, num = nx = 0;
scanf("%d%d%d", &n, &k, &m), ++k;
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].x), ++a[i].x;
b[++num] = a[i].l, b[++num] = a[i].r, bx[++nx] = a[i].x;
}
sort(b + 1, b + 1 + num), num = unique(b + 1, b + 1 + num) - b - 1;
sort(bx + 1, bx + 1 + nx), nx = unique(bx + 1, bx + 1 + nx) - bx - 1;
b[num + 1] = n + 1, n = num * 2 + 1;
Mn::init();
for (int i = 1; i <= m; ++i) {
a[i].l = (lower_bound(b + 1, b + 1 + num, a[i].l) - b) << 1;
a[i].r = (lower_bound(b + 1, b + 1 + num, a[i].r) - b) << 1;
a[i].x = lower_bound(bx + 1, bx + 1 + nx, a[i].x) - bx;
q[a[i].x].push_back(i);
Mn::cover(1, 1, n, a[i].l, a[i].r, a[i].x);
}
Mn::dfs(1, 1, n, inf);
// 3 m log m
for (int i = 1; i <= m; ++i)
if (Mn::ask(1, 1, n, a[i].l, a[i].r) < a[i].x) {
puts("0");
return 0;
}
for (int i = 1; i <= n; ++i)
if (c[i] < inf && len(i)) v[c[i]].push_back(i);
else if (len(i)) mu(ans, qpow(k, len(i)));
for (int x = 1; x <= nx; ++x) {
nf = v[x].size();
for (int i = 1; i <= nf; ++i) f[i] = g[i] = 0;
sort(q[x].begin(), q[x].end(), cmp);
Seg::build(1, 1, nf);
int p = -1;
f[0] = 1;
for (int i = 1; i <= nf; ++i) {
int ln = len(v[x][i - 1]);
long long t = f[i - 1] * ((qpow(bx[x], ln) - qpow(bx[x] - 1, ln) + mod) % mod) % mod;
int nxt = i < nf ? v[x][i] : inf, l = 0;
while (p < int(q[x].size() - 1) && a[q[x][p + 1]].r < nxt) ++p, l = max(l, a[q[x][p]].l);
if (l) {
auto lp = lower_bound(v[x].begin(), v[x].end(), l);
l = lp - v[x].begin() + 1;
}
if (!l) f[i] = f[i - 1] * qpow(bx[x], ln) % mod;
else {
f[i] = (t + Seg::ask(1, 1, nf, l, i - 1) * qpow(bx[x] - 1, ln) % mod) % mod;
Seg::change(1, 1, nf, 1, l - 1, 0, 1);
}
Seg::change(1, 1, nf, i, i, t, 1);
Seg::change(1, 1, nf, 1, i - 1, qpow(bx[x] - 1, ln));
}
mu(ans, f[nf]);
}
printf("%lld\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)