首先通过KMP算法预处理出TT的nextnext数组,设:
pref_iprefi表示SS的前缀ii与TT进行KMP后KMP的指针到达了哪里。
preg_ipregi表示SS的前缀ii中TT出现的次数。
suf_{i,j}sufi,j表示从SS的后缀ii,从jj指针开始KMP,能匹配多少个TT。
那么前缀ii拼接上后缀jj中TT的个数为preg_i+suf_{j,pref_i}pregi+sufj,prefi。
令pregpreg为pregpreg的前缀和,sufsuf为sufsuf的后缀和,s_{i,j}si,j表示ii前面中prefpref为jj的个数,那么对于询问L,RL,R:
ans=\sum_{i=1}^L\sum_{j=R}^n preg_i+suf_{j,pref_i}=(n-R+1)preg_L+\sum_{i=0}^{m-1}s_{L,i}\times suf_{R,i}ans=∑i=1L∑j=Rnpregi+sufj,prefi=(n−R+1)pregL+∑i=0m−1sL,i×sufR,i
以上所有数组均可以使用KMP和递推求出,时间复杂度O((n+k)m)O((n+k)m)。
s数组可以在kmp时预处理出来,suf可以通过预处理递推出来,枚举t字符串每一位和a-z匹配算出新的next数组,用dp的方式预处理出suf
具体看代码:
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <queue> #include <vector> #include <bitset> using namespace std; #define LL long long const int INF = 0x3f3f3f3f; #define mod 10000007 #define mem(a,b) memset(a,b,sizeof a) char s[50005],t[505]; int nt[505],pren[50005],suf[50005][505],sx[50005][505],mat[505][505],nt2[505][505]; void get_next(int x) { nt[0]=0; nt[1]=0; for(int i=2; i<=x; i++) { int k=nt[i-1]; while(k>0&&t[i]!=t[k+1]) k=nt[k]; nt[i]=t[i]==t[k+1]?k+1:0; } } int main() { int m,n,q,T; for(scanf("%d",&T); T--;) { scanf("%d%d%d",&n,&m,&q); scanf("%s%s",s+1,t+1); get_next(m); memset(sx,0,sizeof sx); memset(pren,0,sizeof pren); for(int i=1,j=0; i<=n; i++) { while(j&&s[i]!=t[j+1]) j=nt[j]; if(s[i]==t[j+1]) j++; pren[i]=pren[i-1]; if(j==m) pren[i]++,j=nt[j]; for(int kk=0; kk<m; kk++) sx[i][kk]=sx[i-1][kk]; sx[i][j]++; } for(int i=1; i<=n; i++) pren[i]+=pren[i-1]; memset(mat,0,sizeof mat); for(int i=0; i<m; i++) for(int j='a'; j<='z'; j++) { int k=i; while(k&&t[k+1]!=j) k=nt[k]; if(t[k+1]==j) k++; if(k==m) k=nt[k],mat[i][j]=1; nt2[i][j]=k; } memset(suf,0,sizeof suf); for(int i=n; i>0; i--) { for(int j=0; j<m; j++) suf[i][j]=mat[j][s[i]]+suf[i+1][nt2[j][s[i]]]; } for(int i=n; i>0; i--) { for(int j=0; j<m; j++) suf[i][j]+=suf[i+1][j]; } while(q--) { int l,r; scanf("%d%d",&l,&r); LL ans=1LL*(n-r+1)*pren[l]; for(int i=0; i<m; i++) { ans+=1LL*sx[l][i]*suf[r][i]; } printf("%lld\n",ans); } } return 0; }
