[TJOI2017] DNA
Description
求模式串与主串的匹配次数,容错不超过三个字符。
Solution
枚举每个开始位置,进行暴力匹配,直到失配次数用光或者匹配成功。考虑到容错量很小,所以每个位置开始的匹配过程中大部分与普通匹配是同样操作,而我们需要的其实就是 LCP 长度,所以预处理出后缀数组和高度数组,建 ST 表支持 RMQ 询问,来加速暴力匹配的过程。时间复杂度 \(O(n \log n)\)
#include <bits/stdc++.h> using namespace std; int n,k,l0,m=256,sa[250005],y[250005],u[250005],v[250005],o[250005],r[250005],h[250005],T; char str[250005]; int lg2[250005]; struct clsst { int a[250005][21]; void build(int *src,int n) { for(int i=1;i<=n;i++) a[i][0]=src[i]; for(int i=1;i<=20;i++) for(int j=1;j<=n-(1<<i)+1;j++) a[j][i]=min(a[j][i-1],a[j+(1<<(i-1))][i-1]); } int query(int l,int r) { if(l>r) swap(l,r); int j=lg2[r-l+1]; return min(a[l][j],a[r-(1<<j)+1][j]); } } st; int lcp(clsst *st,int p,int q) { if(r[p]>r[q]) swap(p,q); return st->query(r[p]+1,r[q]); } int match(clsst *st,int p,int q) { return lcp(st,p,l0+1+q); } int matchstr(clsst *st,int p,int q,int x) { if(x<0) return 0; if(q>k-x) return 1; int step = match(st,p,q); //cout<<"matchstr "<<p<<" "<<q<<" "<<x<<" "<<step<<endl; p+=step-1; q+=step-1; if(q>=k-x) return 1; else return matchstr(st,p+2,q+2,x-1); } int main(){ for(int i=1;i<=250000;i++) lg2[i]=log2(i); scanf("%d",&T); while(T--) { memset(sa,0,sizeof sa); memset(y,0,sizeof y); memset(u,0,sizeof u); memset(v,0,sizeof v); memset(o,0,sizeof o); memset(r,0,sizeof r); memset(h,0,sizeof h); memset(str,0,sizeof str); scanf("%s",str+1); n=l0=strlen(str+1); str[n+1]='$'; scanf("%s",str+n+2); k=strlen(str+n+2); n+=k+1; for(int i=1;i<=n;i++) u[str[i]]++; for(int i=1;i<=m;i++) u[i]+=u[i-1]; for(int i=n;i>=1;i--) sa[u[str[i]]--]=i; r[sa[1]]=1; for(int i=2;i<=n;i++) r[sa[i]]=r[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]); for(int l=1;r[sa[n]]<n;l<<=1) { memset(u,0,sizeof u); memset(v,0,sizeof v); memcpy(o,r,sizeof r); for(int i=1;i<=n;i++) u[r[i]]++, v[r[i+l]]++; for(int i=1;i<=n;i++) u[i]+=u[i-1], v[i]+=v[i-1]; for(int i=n;i>=1;i--) y[v[r[i+l]]--]=i; for(int i=n;i>=1;i--) sa[u[r[y[i]]]--]=y[i]; r[sa[1]]=1; for(int i=2;i<=n;i++) r[sa[i]]=r[sa[i-1]]+((o[sa[i]]!=o[sa[i-1]])||(o[sa[i]+l]!=o[sa[i-1]+l])); } { int i,j,k=0; for(int i=1;i<=n;h[r[i++]]=k) for(k?k--:0,j=sa[r[i]-1];str[i+k]==str[j+k];k++); } memset(st.a,0,sizeof st.a); st.build(h,n); int ans = 0; for(int i=1;i<=l0-k+1;i++) { //cout<<"try "<<i<<endl; int tmp = matchstr(&st,i,1,3); //if(tmp==1) cout<<i<<endl; ans += tmp; } cout<<ans<<endl; } }