题意:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b33427a8eb5044cbaa1576111a4b1e53.png)
解法:
如果没有修改操作, 容易想到dp维护每个前缀不出现的最小操作次数.
带修改操作的dp,容易想到线段树维护矩阵乘法.
矩阵乘法性质:
ans[i][j]=op1(ans[i][j],op2(a[i][k],b[k][j]))
这里的op1和op2可以自己定义
经典的矩阵乘法op1为加法,op2为乘法
令d[i][0/1/2]为不存在前缀a,ab,abc的最小操作次数
转移方程:
d[i][0]=d[i-1][0]+(s[i]=='a')
d[i][1]=min(d[i-1][0], d[i-1][1]+(s[i]=='b'))
d[i][2]=min(d[i-1][0], d[i-1][1], d[i-1][2]+(s[i]=='c'))
令op1为min, op2为+
以矩阵形式描述转移方程:
原矩阵x为:
[d[i-1][0]]
[d[i-1][1]]
[d[i-1][2]]
系数矩阵A为:
[s[i]=='a'] [inf] [inf]
[0] [s[i]=='b'] [inf]
[0] [0] [s[i]=='c']
用线段树维护矩阵乘法即可.
Code:
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define int long long
#define PI pair<int, int>
const int maxm=1e5+5;
const int mod=1e9+7;
int n,q;
char s[maxm];
struct Mat{
int a[3][3];
void reset() {
memset(a,0,sizeof a);
}
void init(int c){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(i<j){
a[i][j]=1e9;
} else if(i>j){
a[i][j]=0;
} else {
a[i][j]=(c==i);
}
}
}
}
static int op1(int i,int j){
return min(i,j);
}
static int op2(int i,int j){
return i+j;
}
Mat operator*(const Mat& rhs)const{
Mat ans;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
ans.a[i][j]=1e9;
}
}
for(int k=0;k<3;k++){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
ans.a[i][j]=op1(ans.a[i][j],op2(a[i][k],rhs.a[k][j]));
}
}
}
return ans;
}
void out(){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
cout<<a[i][j]<<' ';
}
cout<<endl;
}
}
};
struct ST{
Mat a[maxm<<2];
void pushup(int k){
a[k]=a[k*2+1]*a[k*2];
}
void init(int l,int r,int k){
if(l==r){
a[k].init(s[l]);
return ;
}
int mid=(l+r)/2;
init(l,mid,k*2);
init(mid+1,r,k*2+1);
pushup(k);
}
void update(int x,int c,int l,int r,int k){
if(l==r){
a[k].init(c);
return ;
}
int mid=(l+r)/2;
if(x<=mid)update(x,c,l,mid,k*2);
else update(x,c,mid+1,r,k*2+1);
pushup(k);
}
}T;
void solve() {
cin>>n>>q;
cin>>(s+1);
for(int i=1;i<=n;i++){
s[i]-='a';
}
T.init(1,n,1);
Mat base;base.reset();
for(int i=1;i<=q;i++){
int x;cin>>x;
char c;cin>>c;c-='a';
T.update(x,c,1,n,1);
Mat dp=T.a[1]*base;
int ans=dp.a[2][0];
cout<<ans<<endl;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
#ifndef ONLINE_JUDGE
freopen("../in.txt", "r", stdin);
freopen("../out.txt", "w", stdout);
#endif
#ifdef MULTI_CASE
int T;
cin >> T;
while (T--)
#endif
solve();
return 0;
}