【题解】Luogu P6864 [RC-03] 记忆

Luogu P6864 [RC-03] 记忆

题目分析:

如果没有操作 3,那么这个题是很简单的。
我们设原串有 ans 个子串是能匹配的,有 cnt 个后缀是能匹配的。
操作一即:ansans+cnt+1cntcnt+1
操作二即:ansans+1cnt1
而对于操作三,显然每一个操作只会对应一个操作 1 或操作 2 的修改,所以可以读入的时候就直接处理出来当前的操作会影响哪个操作。
那么这个操作三其实就相当于支持在操作序列上任意插入或删除一个操作了,有一种 ddp 的既视感。
其实只要和 ddp 联系起来就很简单了,会发现操作 1,2 就相当于一个矩阵乘法,所以删除就相当于更改为单位矩阵,插入就相当于更改为对应的矩阵,直接上线段树维护矩阵乘就好了。

最后就把我自己推的矩阵给列出来了:

维护的矩阵:

[anscnt1]

操作 1 的矩阵:

[100110111]

操作 2 的矩阵:

[100000111]

代码:

点击查看代码
#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;
}
posted @   linyihdfj  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示