[题解] [USACO23OPEN] Pareidolia P
首先考虑对于单独的一个数列应该怎么做。
记字符串 bessie 为
考虑一个 dp:记
那么有转移:
考虑用 cdq 分治维护这个过程,记当前分治区间为
对于每个区间,记录
合并
这个分治的过程显然可以用线段树维护,时间复杂度
code:
#include<bits/stdc++.h>
#define int long long
#define MAXN 200010
using namespace std;
const string base="bessie";
int n,Q;
char s[MAXN];
struct tnode{
int nxt[6],cnt[6],co[6],sum;
tnode(char c='#',int pos=0){
memset(nxt,0,sizeof(nxt));memset(cnt,0,sizeof(cnt));
memset(co,0,sizeof(co));sum=0;
if(pos){
for(int i=0;i<6;i++)nxt[i]=(c==base[i]?(i+1)%6:i);
cnt[nxt[0]]=1;co[5]=(c=='e'?n-pos+1:0);
}
}
};
tnode operator+(tnode ql,tnode qr){
tnode ret;ret.sum=ql.sum+qr.sum;
for(int i=0;i<6;i++){
ret.nxt[i]=qr.nxt[ql.nxt[i]];
ret.cnt[i]+=qr.cnt[i];ret.cnt[qr.nxt[i]]+=ql.cnt[i];
ret.co[i]=ql.co[i]+qr.co[ql.nxt[i]];
ret.sum+=ql.cnt[i]*qr.co[i];
}
return ret;
}
struct Segtree{
tnode t[MAXN<<2];
void pushup(int p){t[p]=t[p<<1]+t[p<<1|1];}
void build(int p,int l,int r){
if(l==r)return (void)(t[p]=tnode(s[l],l));int mid=(l+r)>>1;
build(p<<1,l,mid);build(p<<1|1,mid+1,r);pushup(p);
}
void update(int p,int l,int r,int pos,char d){
if(l==r)return (void)(t[p]=tnode(d,l));
int mid=(l+r)>>1;
if(pos<=mid)update(p<<1,l,mid,pos,d);
else update(p<<1|1,mid+1,r,pos,d);
pushup(p);
}
}T;
signed main(){
scanf("%s%lld",s+1,&Q);n=strlen(s+1);
T.build(1,1,n);
printf("%lld\n",T.t[1].sum);
while(Q--){
int pos;char opt[2];scanf("%lld%s",&pos,opt);
T.update(1,1,n,pos,opt[0]);
printf("%lld\n",T.t[1].sum);
}
return 0;
}