题目链接:Classic Quotation
题意:给定两个字符串S和T,然后给出k个询问,每次询问输入L,R,输出S的1,i和j,n拼接成的字符串中出现字符串T的期望次数。
题解:记A_i表示字符串S的[1,i]能匹配多少个T,
prei=∑ij=1Ai
,B_(i,j)表示T匹配完S中[1,i]的字符后kmp指针指向的位置。
cnti,j=∑ik=1Bk,j
。C_{i,j}表示kmp指针指向j时从S[i]处匹配能匹配到多少个T,
sufi,j=∑nk=iCk,j
。那么
ANS=L∗(n−R+1)∗1L∗∑i=1L(Ai+∑j=0T.length+1(cnti,j∗1n−R+1∗∑k=RnCk,j))
=(n−R+1)∗preL+∑T.length+1j=0(cntj,i∗sufj,R)
#include <bits/stdc++.h>
using namespace std;
const int N = 50005;
char s[N],t[105];
int pre[N],cnt[N][105],suf[N][105],nxt[105];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m,k,l,r;
scanf("%d %d %d",&n,&m,&k);
scanf(" %s %s",s+1,t+1);
int i=0,j=1;
nxt[1]=0;
while(j<=m)
if(!i||t[i]==t[j])
nxt[++j]=++i;
else
i=nxt[i];
i=j=1;
memset(cnt,0,sizeof cnt);
memset(pre,0,sizeof pre);
memset(suf,0,sizeof suf);
while(j<=n)
if(!i||t[i]==s[j]){
i++;
j++;
cnt[j-1][i]++;
if(i==m+1)
pre[j-1]++;
}else
i=nxt[i];
for(int i=1;i<=n;i++){
pre[i]+=pre[i-1];
for(int j=0;j<=m+1;j++)
cnt[i][j]+=cnt[i-1][j];
}
for(int i=1;i<=n;i++)
pre[i]+=pre[i-1];
for(int p=n;p>=1;p--)
for(int q=0;q<=m+1;q++){
int l=p,r=q;
for(;;)
if(!r||s[l]==t[r]){
l++;
r++;
break;
}else
r=nxt[r];
suf[p][q]+=suf[l][r]+(r==m+1?1:0);
}
for(int i=n-1;i>=1;i--)
for(int j=0;j<=m+1;j++)
suf[i][j]+=suf[i+1][j];
while(k--){
scanf("%d %d",&l,&r);
long long ans=1LL*(n-r+1)*pre[l];
for(int i=0;i<=m+1;i++)
ans+=1LL*cnt[l][i]*suf[r][i];
printf("%lld\n",ans);
}
}
return 0;
}