发现很早以前用exkmp做过一次,但是对这题来说只要将两个串翻转一下即可转换成s2的所有前缀出现的问题
/* 给出s1,s2,求s2的每个后缀在s1中出现的次数 ans = sum{后缀长度*出现次数} 思路:把数组倒过来,求s2的nxt数组 cnt[i]当匹配到s2的第i位可以对答案做的贡献 cnt[i]=当前与s1第i个字符配对的s2的前缀长度+cnt[nxt[j]] */ #include<iostream> #include<cstring> #include<cstdio> using namespace std; #define mod 1000000007 #define maxn 1000005 #define ll long long char s1[maxn],s2[maxn]; int nxt[maxn],m,cnt[maxn],ans; void reserve(char *s){ int len=strlen(s); int i=0,j=len-1; while(i<j){ swap(s[i],s[j]); ++i,--j; } } void kmp_pre(char *s){ memset(nxt,0,sizeof nxt); int m=strlen(s); int i,j; i=0,j=nxt[0]=-1; while(i<m){ while(j!=-1 && s[i]!=s[j]) j=nxt[j]; nxt[++i]=++j; } for(int i=1;i<=m;i++) cnt[i]=(i+cnt[nxt[i]])%mod; } void kmp(){ int n=strlen(s1),m=strlen(s2); int i=0,j=0; while(i<n){ while(j!=-1 && s1[i]!=s2[j]) j=nxt[j]; ++i,++j; ans=(ans+cnt[j])%mod; if(j==m)j=nxt[j]; } } int main(){ int t; scanf("%d",&t); while(t--){ memset(cnt,0,sizeof cnt); scanf("%s%s",s1,s2); reserve(s1); reserve(s2); kmp_pre(s2); ans=0; kmp(); printf("%d ",ans); } }