ABC246Ex
DDP 板子。
设 fi,0/1 表示前 i 位,以 0/1 结尾的本质不同子序列有多少种。
则最终答案就是 fn,0+fn,1。
考虑转移,以当前字符为 0
为例,则有
fi,0=fi−1,0+fi−1,1+1,fi,1=fi−1,1
解释一下,显然 fi,0/1 都能继承 fi−1,0/1,而 fi,0 新增的部分是在前面每一个以 1
结尾的本质不同子序列后面放尽量多的 0
然后再放一个 0
,而且也可以全部放 0
,所以新增的部分是 fi−1,1+1。
于是同理,当前字符为 1
,则有
fi,0=fi−1,0,fi,1=fi−1,0+fi−1,1+1
当前字符为 ?
,则有
fi,0=fi−1,0+fi−1,1+1,fi,1=fi−1,0+fi−1,1+1
不难发现可以写成矩阵形式,即
-
当前字符为
0
,[fi+1,0fi+1,11]=[fi,0fi,11][100110101] -
当前字符为
1
,[fi+1,0fi+1,11]=[fi,0fi,11][110010011] -
当前字符为
?
,[fi+1,0fi+1,11]=[fi,0fi,11][110110111]
因为还要支持带修,于是用线段树维护矩阵即可。
思考清楚后代码写起来很快,没记错的话我当时写了 15 分钟一遍过。
Code:
#include <bits/stdc++.h>
using namespace std;
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
typedef long long ll;
const int N = 100005, mod = 998244353;
int n, Q;
char s[N];
struct mat {
int a[3][3];
mat operator * (const mat &x) const {
mat res; memset(res.a, 0, sizeof res.a);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
res.a[i][j] = (res.a[i][j] + 1ll * a[i][k] * x.a[k][j] % mod) % mod;
return res;
}
} f;
mat calc(char ch) {
mat res; memset(res.a, 0, sizeof res.a);
if (ch == '0') {
res.a[0][0] = res.a[1][0] = res.a[1][1] = res.a[2][0] = res.a[2][2] = 1;
}
else if (ch == '1') {
res.a[0][0] = res.a[0][1] = res.a[1][1] = res.a[2][1] = res.a[2][2] = 1;
}
else {
res.a[0][0] = res.a[1][0] = res.a[2][0] = res.a[0][1] = res.a[1][1] = res.a[2][1] = res.a[2][2] = 1;
}
return res;
}
struct Segment_Tree {
mat val[N*4];
void pushup(int p) { val[p] = val[ls(p)] * val[rs(p)]; }
void build(int p, int l, int r) {
if (l == r) return void(val[p] = calc(s[l]));
int mid = l + r >> 1;
build(ls(p), l, mid), build(rs(p), mid + 1, r);
pushup(p);
}
void change(int p, int l, int r, int x, char v) {
if (l == r) return void(val[p] = calc(v));
int mid = l + r >> 1;
if (x <= mid) change(ls(p), l, mid, x, v);
else change(rs(p), mid + 1, r, x, v);
pushup(p);
}
} sTr;
int main() {
memset(f.a, 0, sizeof f.a); f.a[0][2] = 1;
scanf("%d%d", &n, &Q);
scanf("%s", s + 1);
sTr.build(1, 1, n);
while (Q--) {
int x; char ch[2]; scanf("%d%s", &x, ch);
sTr.change(1, 1, n, x, ch[0]);
mat tmp = f * sTr.val[1];
printf("%d\n", (tmp.a[0][0] + tmp.a[0][1]) % mod);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话