P6864 RC-03 记忆
设当前括号串
- 合法括号非空 子串 数量为
。 - 合法括号非空 后缀子串 数量为
。
例:
,则 , 。
设
现试图找到
不难发现
再设
我们试图证明,新增的合法括号非空子串只有
反证法,我们考虑有没有可能,新加的这对括号中的左括号,和
很明显,这要求
但在操作的变换中,字符串始终是合法括号串。因此,
那有无可能,新加的这对括号中的右括号,和
这要求
可以发现,这就意味着
那么新增的合法括号子串只有
所以
现在考虑撤销操作。发现撤销操作对
然后这里有一个比较不朴素的想法……那就是用矩阵刻画上面两种操作的变换。
刻画还是较为容易的:
那么答案可以看做初始矩阵
那撤销是什么?题目的撤销还可以撤销一个撤销操作,看起来很高级,但它的影响最后无非都是:
- 将某个非撤销操作(即操作一或操作二)从进行改为不进行。
- 将某个非撤销操作(即操作一或操作二)从不进行改为进行。
不进行操作也是可以刻画出矩阵的,即单位矩阵
所以任何一个撤销操作都是将一个非撤销操作对应的矩阵单点修改,要么是从操作矩阵修改成单位矩阵,要么是从单位矩阵修改成操作矩阵。
因此现在变成一个对矩阵单点修改,求矩阵全局乘法的问题。因为矩阵乘法有结合律,可以用线段树维护。
因为矩阵乘法没法差分,所以不能用单
时间复杂度
/*
* @Author: crab-in-the-northeast
* @Date: 2023-05-15 16:06:19
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2023-05-15 19:15:26
*/
#include <bits/stdc++.h>
#define int long long
inline int read() {
int x = 0;
bool f = true;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-')
f = false;
for (; isdigit(ch); ch = getchar())
x = (x << 1) + (x << 3) + ch - '0';
return f ? x : (~(x - 1));
}
inline int ls(int p) {
return p << 1;
}
inline int rs(int p) {
return p << 1 | 1;
}
struct phalanx {
int a[4][4];
phalanx () {
for (int i = 1; i <= 3; ++i)
for (int j = 1; j <= 3; ++j)
a[i][j] = 0;
}
phalanx (std :: vector <int> v) {
for (int i = 1; i <= 3; ++i)
for (int j = 1; j <= 3; ++j)
a[i][j] = v[(i - 1) * 3 + j - 1];
}
const phalanx operator * (const phalanx b) const {
phalanx ans;
for (int i = 1; i <= 3; ++i)
for (int j = 1; j <= 3; ++j)
for (int k = 1; k <= 3; ++k)
ans.a[i][j] += a[i][k] * b.a[k][j];
return ans;
}
};
const phalanx UNIT({1, 0, 0, 0, 1, 0, 0, 0, 1}),
OP1({1, 0, 0, 1, 1, 0, 1, 1, 1}),
OP2({1, 0, 0, 0, 0, 0, 1, 1, 1});
const int N = (int)2e5 + 5;
struct node {
int l, r;
phalanx ans;
} t[N << 2];
inline node con(node lef, node rgt) {
return (node){
l: lef.l,
r: rgt.r,
ans: lef.ans * rgt.ans
};
}
inline void up(int p) {
t[p] = con(t[ls(p)], t[rs(p)]);
}
void build(int p, int l, int r) {
if (l == r) {
t[p].l = t[p].r = l;
t[p].ans = UNIT;
return ;
}
int mid = (l + r) >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
up(p);
}
void modify(int p, int x, int op) {
int l = t[p].l, r = t[p].r;
if (l == r) {
if (op == 1)
t[p].ans = OP1;
else if (op == 2)
t[p].ans = OP2;
else
t[p].ans = UNIT;
return ;
}
int mid = (l + r) >> 1;
if (x <= mid)
modify(ls(p), x, op);
else
modify(rs(p), x, op);
up(p);
}
int ops[N];
int pos[N];
signed main() {
int n = read();
build(1, 1, n);
for (int i = 1; i <= n; ++i) {
int op = ops[i] = read();
pos[i] = i;
if (op <= 2)
modify(1, i, op);
else {
int p = read();
p = pos[i] = pos[p];
ops[p] = -ops[p];
modify(1, p, ops[p]);
}
phalanx ans = t[1].ans;
printf("%lld\n", ans.a[1][1] + ans.a[2][1] + ans.a[3][1]);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】