枚举$B$串的每个后缀,统计出该后缀所有满足条件的前缀。
考虑暴力搜索,设状态$(x,y,z)$表示当前需要考虑$A$从$x$开始的后缀,$B$从$y$开始的后缀,之前部分编辑距离为$z$。
那么首先用后缀数组+ST表求出两个后缀的lcp,$x$和$y$都可以向右跳那么多,且不产生任何代价。
如果此时匹配到了底,那么可以得到在一段区间$[L,R]$内,所有前缀都是合法的。注意到这种前缀只有$2K+1$种,所以可以使用差分前缀和来进行标记。
如果还没有匹配到底,那么有$3$种选择,分别是状态$(x+1,y,z+1)$、$(x,y+1,z+1)$以及$(x+1,y+1,z+1)$。
时间复杂度$O(n\log n+n3^k)$。
#include<cstdio> #include<cstring> #include<algorithm> #define N 100010 using namespace std; char s[N],A[N],B[N]; int K,na,nb,n,m,i,j,rk[N],sa[N],height[N],tmp[N],cnt[N],Log[N],f[17][N],c[15],ans; void suffixarray(int n,int m){ int i,j,k;n++; for(i=0;i<n;i++)cnt[rk[i]=s[i]]++; for(i=1;i<m;i++)cnt[i]+=cnt[i-1]; for(i=0;i<n;i++)sa[--cnt[rk[i]]]=i; for(k=1;k<=n;k<<=1){ for(i=0;i<n;i++){ j=sa[i]-k; if(j<0)j+=n; tmp[cnt[rk[j]]++]=j; } sa[tmp[cnt[0]=0]]=j=0; for(i=1;i<n;i++){ if(rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k])cnt[++j]=i; sa[tmp[i]]=j; } memcpy(rk,sa,n*sizeof(int)); memcpy(sa,tmp,n*sizeof(int)); if(j>=n-1)break; } for(j=rk[height[i=k=0]=0];i<n-1;i++,k++) while(~k&&s[i]!=s[sa[j-1]+k])height[j]=k--,j=rk[sa[j]+1]; } inline int ask(int x,int y){ int k=Log[y-x+1]; return min(f[k][x],f[k][y-(1<<k)+1]); } inline int lcp(int x,int y){ if(x>=na||y>=nb)return 0; x=rk[x],y=rk[y+na+1]; if(x>y)swap(x,y); return ask(x+1,y); } inline void col(int l,int r){ if(l<i)l=i; if(r>=nb)r=nb-1; c[l-i-na+K+2]++,c[r-i-na+K+3]--; } void dfs(int x,int y,int z){ int t=lcp(x,y); x+=t,y+=t; if(x==na||y==nb){ int c=K-(z+na-x); if(c>=0)col(y-1-c,y-1+c); return; } if(z==K)return; z++; dfs(x+1,y,z); dfs(x,y+1,z); dfs(x+1,y+1,z); } int main(){ scanf("%d%s%s",&K,A,B); na=strlen(A),nb=strlen(B); for(i=0;i<na;i++)s[n++]=A[i]; s[n++]='#'; for(i=0;i<nb;i++)s[n++]=B[i]; suffixarray(n,128); for(i=2;i<=n;i++)Log[i]=Log[i>>1]+1; for(i=1;i<=n;i++)f[0][i]=height[i]; for(j=1;j<17;j++)for(i=1;i+(1<<j-1)<=n;i++)f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]); for(m=2*K+1,i=0;i<nb;i++){ for(j=1;j<=m;j++)c[j]=0; dfs(0,i,0); for(j=1;j<=m;j++)if(c[j]+=c[j-1])ans++; } return printf("%d",ans),0; }