专栏文章
JOISC2022 错误拼写 Sol
P9522题解参与者 4已保存评论 4
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @mir05x1r
- 此快照首次捕获于
- 2025/12/04 13:35 3 个月前
- 此快照最后确认于
- 2025/12/04 13:35 3 个月前
实在是绷不住了,做 JOISC 做到梦熊炼石原题,这下这下了。
限制 告诉你啥呢,告诉你这 这个区间要么全部相等,要么第一个相邻不同的位置是左边大于右边; 就是反过来,要么相等要么第一个相邻不同的位置左边小于右边。
考虑 dp, 表示考虑了 , 这个位置填的 这个字符。如果暴力转移就是枚举下一个不同的位置,判断合不合法并计算贡献。复杂度是 。
你去想判断合不合法的过程是怎么样的,就是把所有左端点 的限制区间全扔下标上,进行一个判断。那我们发现你 从右边来的时候,会增加一部分区间,改变一些位置的限制条件(即转移方式)。具体地,一个位置被转移的方式有:
- 不被覆盖
- 仅被 的覆盖
- 仅被 的覆盖
- 被两者同时覆盖
然后发现每个点的状态最多被改变 次。我们只要快速找到哪些点的覆盖状态发生了改变,用 set 维护每种状态的位置即可。复杂度 。
CPPsigned main() {
n = read(), m = read();
rep(i, 1, m) {
int x = read(), y = read(), f = 0;
if (x == y) continue;
if (x > y) swap(x, y), f ^= 1;
p[x].push_back({y, f});
}
rep(j, 0, 25) f[n][j] = 1, ge[j] = 1;
se.insert(n);
per(i, n - 1, 1) {
for (pii j : p[i]) {
int l = i, r = j.fs, fl = j.sc;
if (fl) {
auto it = se.lower_bound(l + 1);
while (it != se.end() && *it <= r) {
s1.insert(*it);
rep(k, 0, 25) g1[k] += f[*it][k], ge[k] -= f[*it][k];
se.erase(it++);
}
it = s0.lower_bound(l + 1);
while (it != s0.end() && *it <= r) {
s2.insert(*it);
rep(k, 0, 25) g0[k] -= f[*it][k];
s0.erase(it++);
}
} else {
auto it = se.lower_bound(l + 1);
while (it != se.end() && *it <= r) {
s0.insert(*it);
rep(k, 0, 25) g0[k] += f[*it][k], ge[k] -= f[*it][k];
se.erase(it++);
}
it = s1.lower_bound(l + 1);
while (it != s1.end() && *it <= r) {
s2.insert(*it);
rep(k, 0, 25) g1[k] -= f[*it][k];
s1.erase(it++);
}
}
}
int s = 0;
rep(j, 0, 25) (s += ge[j]) %= mod;
rep(j, 0, 25) f[i][j] += (s - ge[j] % mod + mod) % mod;
s = 0;
per(j, 25, 0) {
(f[i][j] += s) %= mod;
(s += g0[j] % mod) %= mod;
}
s = 0;
rep(j, 0, 25) {
(f[i][j] += s) %= mod;
(s += g1[j]) %= mod;
}
rep(j, 0, 25) f[i][j]++, f[i][j] %= mod;
se.insert(i);
rep(j, 0, 25) ge[j] += f[i][j];
}
int ans = 0;
rep(j, 0, 25) (ans += f[1][j]) %= mod;
write(ans);
return 0;
}
相关推荐
评论
共 4 条评论,欢迎与作者交流。
正在加载评论...