题意:给两个字符串s和t,求t的每个后缀的长度乘以它在s中出现的次数之和。
用了扩展KMP的板子,因为扩展KMP求出的
extend[i]
表示的是
s
的
for (int i=0;i<slen;i++){
if (extend[i]){
for (int j=1;j<=extend[i];j++)
res[j]++;
}
}
一开始我是这么写的,然后TLE了……发现自己sb了,直接求和不就完了……
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000000+10;
const ll mod=1e9+7;
int T;
char s[maxn];
char t[maxn];
int nxt[maxn];
int extend[maxn];
//next[i]:x[i...m-1]与x[0...m-1]的最长公共前缀
void pre_ex_kmp(char x[],int m){
nxt[0]=m;
int j=0;
while (j+1<m&&x[j]==x[j+1])
j++;
nxt[1]=j;
int k=1;
for (int i=2;i<m;i++){
int p=nxt[k]+k-1;
int L=nxt[i-k];
if (i+L<p+1)
nxt[i]=L;
else{
j=max(0,p-i+1);
while (i+j<m&&x[i+j]==x[j])
j++;
nxt[i]=j;
k=i;
}
}
}
//extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀
void ex_kmp(char x[],int m,char y[],int n){
pre_ex_kmp(x,m);
int j=0;
while (j<n&&j<m&&x[j]==y[j])
j++;
extend[0]=j;
int k=0;
for (int i=1;i<n;i++){
int p=extend[k]+k-1;
int L=nxt[i-k];
if (i+L<p+1)
extend[i]=L;
else{
j=max(0,p-i+1);
while (i+j<n&&j<m&&y[i+j]==x[j])
j++;
extend[i]=j;
k=i;
}
}
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%s",s);
scanf("%s",t);
int slen=strlen(s);
int tlen=strlen(t);
reverse(s,s+strlen(s));
reverse(t,t+strlen(t));
ex_kmp(t,tlen,s,slen);
ll ans=0;
for (int i=0;i<slen;i++){
if (extend[i]){
ans+=(extend[i]%mod)*((extend[i]+1)%mod)/2;
ans%=mod;
}
}
printf("%lld\n",ans);
}
}