【题解】Luogu P6864 [RC-03] 记忆
Luogu P6864 [RC-03] 记忆
题目分析:
如果没有操作 \(3\),那么这个题是很简单的。
我们设原串有 \(ans\) 个子串是能匹配的,有 \(cnt\) 个后缀是能匹配的。
操作一即:\(ans \to ans + cnt + 1\) 且 \(cnt \to cnt + 1\)
操作二即:\(ans \to ans + 1\) 且 \(cnt \to 1\)
而对于操作三,显然每一个操作只会对应一个操作 \(1\) 或操作 \(2\) 的修改,所以可以读入的时候就直接处理出来当前的操作会影响哪个操作。
那么这个操作三其实就相当于支持在操作序列上任意插入或删除一个操作了,有一种 \(ddp\) 的既视感。
其实只要和 \(ddp\) 联系起来就很简单了,会发现操作 \(1,2\) 就相当于一个矩阵乘法,所以删除就相当于更改为单位矩阵,插入就相当于更改为对应的矩阵,直接上线段树维护矩阵乘就好了。
最后就把我自己推的矩阵给列出来了:
维护的矩阵:
\[\begin{bmatrix}
ans & cnt & 1
\end{bmatrix}
\]
操作 \(1\) 的矩阵:
\[\begin{bmatrix}
1 & 0 & 0 \\
1 & 1 & 0 \\
1 & 1 & 1 \\
\end{bmatrix}
\]
操作 \(2\) 的矩阵:
\[\begin{bmatrix}
1 & 0 & 0 \\
0 & 0 & 0 \\
1 & 1 & 1 \\
\end{bmatrix}
\]
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5+5;
struct Mar{
int v[4][4];
Mar(){memset(v,0,sizeof(v));}
}tree[4*N],T[4];
int f[N],op[N];
bool flag[N];
Mar operator * (Mar a,Mar b){
Mar c;
for(int i=1; i<=3; i++){
for(int j=1; j<=3; j++){
for(int k=1; k<=3; k++){
c.v[i][j] += a.v[i][k] * b.v[k][j];
}
}
}
return c;
}
void build(int now,int now_l,int now_r){
if(now_l == now_r){
tree[now] = T[3];
return;
}
int mid = (now_l + now_r)>>1;
build(now<<1,now_l,mid);build(now<<1|1,mid+1,now_r);
tree[now] = tree[now<<1] * tree[now<<1|1];
}
void modify(int now,int now_l,int now_r,int pos,int opt){
if(now_l == now_r){
tree[now] = T[opt];
return;
}
int mid = (now_l + now_r)>>1;
if(pos <= mid) modify(now<<1,now_l,mid,pos,opt);
if(pos > mid) modify(now<<1|1,mid+1,now_r,pos,opt);
tree[now] = tree[now<<1] * tree[now<<1|1];
}
signed main(){
T[1].v[1][1] = T[1].v[2][1] = T[1].v[2][2] = T[1].v[3][1] = T[1].v[3][2] = T[1].v[3][3] = 1; //操作 1
T[2].v[1][1] = T[2].v[3][1] = T[2].v[3][2] = T[2].v[3][3] = 1; //操作 2
T[3].v[1][1] = T[3].v[2][2] = T[3].v[3][3] = 1; //单位矩阵
int n;scanf("%lld",&n);
build(1,1,n);
for(int i=1; i<=n; i++){
scanf("%lld",&op[i]);
if(op[i] == 1){
f[i] = i;
modify(1,1,n,i,1);
}
else if(op[i] == 2){
f[i] = i;
modify(1,1,n,i,2);
}
else if(op[i] == 3){
scanf("%lld",&f[i]);
f[i] = f[f[i]];
if(flag[f[i]]){ //被删除过
flag[f[i]] = false;
modify(1,1,n,f[i],op[f[i]]);
}
else{
flag[f[i]] = true;
modify(1,1,n,f[i],3);
}
}
Mar ans;
//1,2,3:ans cnt 1
ans.v[1][1] = ans.v[1][2] = ans.v[1][3] = 1; //注意初始时是一对括号,不是空
ans = ans * tree[1];
printf("%lld\n",ans.v[1][1]);
}
return 0;
}