洛谷P6864 [RC-03] 记忆
洛谷P6864 [RC-03] 记忆
今日模拟赛,看见此题,苦思冥想许久,度一时辰,未果,见洛谷一番目题解与吾之胡思甚像,懊悔不已,又见矩阵线段树做法,码甚清晰,大喜,故记之。
显然有一个暴力分,如果没有 \(3\) 操作,那么简记当前的括号序列 \(\underbrace{()()() \dots ()}_{k个}\)。
如果加上操作 \(1\),\(k \to k+1\),对答案贡献为 \(k+1\)(因为右端为加入的括号,左端随便选)。
如果加上操作 \(2\),\(k = 1\),对答案贡献为 \(1\)。
这显然是 \(O(n)\) 的。
直接讲正解。
因为有了操作 \(3\),我们构造矩阵 \(\begin{bmatrix} ans&k&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}\)。
对于操作 \(3\),让矩阵在单位矩阵与操作矩阵间来回翻转就可以了。
\(\huge \mathscr{Code}\)
#include<iostream>
#include<cstring>
#define int long long
#define mem(a) memset((a),0,sizeof (a))
using namespace std;
const int N = 2e5+100;
int n,ans,x,canc[N],operate[N],rec[N];
struct Matrix{
int m[4][4];
friend Matrix operator *(Matrix a,Matrix b){
Matrix p;
memset(p.m,0,sizeof(p));
for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) for(int k=1;k<=3;k++) p.m[i][j] += a.m[i][k]*b.m[k][j];
return p;
}
void Print_Matrix(){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cout<<m[i][j]<<' ';
}cout<<'\n';
}
}
};
void Normal(Matrix &p) {mem(p.m),p.m[1][1] = p.m[2][2] = p.m[3][3] = 1;}
void Op1(Matrix &p) {mem(p.m),p.m[1][1] = p.m[2][2] = p.m[3][3] = p.m[2][1] = p.m[3][1] = p.m[3][2] = 1;}
void Op2(Matrix &p) {mem(p.m),p.m[1][1] = p.m[3][1] = p.m[3][2] = p.m[3][3] = 1;}
struct node{
int l,r;
Matrix ans;
}T[N<<2];
void pushup(int u){
T[u].ans = T[u*2].ans*T[u*2+1].ans;
}
void build(int u,int l,int r){
T[u].l = l,T[u].r = r;
if(l==r){
Normal(T[u].ans);
return;
}
int mid = (T[u].l+T[u].r)>>1;
build(u*2,l,mid),build(u*2+1,mid+1,r);
pushup(u);
}
void update(int u,int q,int op){
if(T[u].l==T[u].r){
op==3?Normal(T[u].ans):op==1?Op1(T[u].ans):Op2(T[u].ans);
return;
}
int mid = (T[u].l+T[u].r)>>1;
if(q<=mid) update(u*2,q,op);
else update(u*2+1,q,op);
pushup(u);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
build(1,1,n);
for(int i=1;i<=n;i++){
rec[i] = i;
cin>>operate[i];
if(operate[i]==3){
cin>>x;
rec[i] = rec[x];
canc[rec[i]] ^= 1;
update(1,rec[i],canc[rec[i]]?3:operate[rec[i]]);
}
if(operate[i]==2) update(1,i,2);
if(operate[i]==1) update(1,i,1);
Matrix p;
mem(p.m);
p.m[1][1] = p.m[1][2] = p.m[1][3] = 1;
p = p*T[1].ans;
cout<<p.m[1][1]<<'\n';
}
return 0;
}
小结:什么时候可以想到矩阵乘法?
首先当前操作对之后的操作没有影响。
其次,操作后的贡献只取决于之前的贡献。

浙公网安备 33010602011771号