1 条题解
-
0
自动搬运
来自洛谷,原作者为

Isonan
**搬运于
2025-08-24 22:09:04,当前版本为作者最后更新于2019-04-09 21:01:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
(此题考查了对KMP的理解以及
乱搞能力有理有据的优化)首先对于可持久化的操作,我们可以将其离线下来并在操作树上dfs。
题意显然可以转化为对一个字符串做KMP,并求。
现在我们考虑已经有了一些字段,现在要在后面加入一个新的字段,如何计算新字段的贡献。
我们可以从之前的最后一个字符开始跳,如果跳到一个位置,它后面正好有一长串长度为的,我们就可以进行匹配。
由于保证了不同于之前的最后一个字符,我们知道如果跳到某个字段的中间,那么它是一定没有用的,可以自己yy一下。
所以我们定义为从当前的第个字段的最后一个点开始,一直跳KMP的所跳到的第一个点所在的字段,满足该点是其所在字段的最后一个字符。
以上算法大概是50分,由于数据过水,实际可以AC。
对于hack数据,我们考虑如何使其复杂度正确。(以下优化借鉴于@142857cs的代码orz)
每次跳时,我们考虑进行一些优化:
如果当前字符串存在周期,我们直接跳到所有周期的第一个。
否则就和原来一样跳。
这样显然每次长度至少,复杂度就不需要均摊了,直接就是
(如有错误请不吝赐教)
代码:
// luogu-judger-enable-o2 // luogu-judger-enable-o2 #include <cstdio> #include <vector> #include <map> #include <algorithm> using std::min; std::map<std::pair<char,short>,int>ma[100001]; char get(){ char ch=getchar(); while(ch<'a'||ch>'z')ch=getchar(); return ch; } int end[100010],pre[100010],cnt,n,length[100010],nxt[100010],ope[100010][2],len,P=998244353,f[100001]; int head[100010],Nxt[200010],b[200010],k,cn; void push(int s,int t){ Nxt[++k]=head[s]; head[s]=k; b[k]=t; } long long ans[100010],fin[100010],val[100010][3]; inline long long getsum(register long long l,register long long r){ if(l>r)return 0; return (l+r)*(r-l+1)/2; } void dfs(int x,int f){ if(ope[x][0]){ int tem=nxt[len]; ++len; ans[len]=0; val[len][0]=ope[x][0]; val[len][1]=ope[x][1]; val[len][2]=val[len-1][2]+ope[x][1]; nxt[len]=0; if(len==1){ ans[len]=getsum(1,val[1][1]-1); } else{ int lastgap=len-tem; while(tem&&(val[tem+1][0]!=ope[x][0]||val[tem+1][1]!=ope[x][1])){ if(tem-nxt[tem]==lastgap)tem=tem%lastgap+lastgap; lastgap=tem-nxt[tem]; tem=nxt[tem]; } if(tem||(val[1][0]==ope[x][0]&&val[1][1]<=ope[x][1]))nxt[len]=tem+1; else nxt[len]=tem; tem=nxt[len-1]; lastgap=len-1-tem; long long lastlength=0; while(lastlength<val[len][1]&&tem){ if(val[tem+1][0]==ope[x][0]&&val[tem+1][1]>lastlength){ ans[len]+=getsum(val[tem][2]+lastlength+1,val[tem][2]+min(val[tem+1][1],val[len][1])); lastlength=val[tem+1][1]; } if(tem-nxt[tem]==lastgap)tem=tem%lastgap+lastgap; lastgap=tem-nxt[tem]; tem=nxt[tem]; } if(lastlength<val[len][1]&&val[1][0]==val[len][0]){ ans[len]+=getsum(lastlength+1,min(val[len][1],val[1][1])); lastlength=std::max(lastlength,min(val[len][1],val[1][1])); ans[len]+=val[1][1]*(val[len][1]-lastlength); } ans[len]+=ans[len-1]; } } fin[x]=ans[len]; for(int i=head[x];i;i=Nxt[i]){ dfs(b[i],x); } if(ope[x][0])--len; } int read(){ int x=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x; } void write(long long x){ if(x>9)write(x/10); putchar((x%10)+'0'); } signed main(){ scanf("%d",&n); for(int i=1,opt,x;i<=n;i++){ opt=read(),x=read(); if(opt==1){ ope[i][0]=get(); ope[i][1]=x; auto y=std::make_pair(ope[i][0],ope[i][1]); f[i]=ma[f[i-1]][y]; if(!f[i]) ma[f[i-1]][y]=i,push(f[i-1],i),f[i]=i; } else{ f[i]=f[x]; } } dfs(0,-1); for(int i=1;i<=n;i++)write(fin[f[i]]%P),putchar('\n'); }
- 1
信息
- ID
- 4269
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者