题目链接:https://cn.vjudge.net/contest/283743#problem/A
题目大意:给你字符串s1和s2,然后问你s2的每一个后缀在s1中出现的次数之和(可重叠)。
具体思路:首先将s1和s2翻转过来,这样的话就把后缀问题转换成了求前缀的问题。举个例子,s1="abcd",s2="cd",将两个字符串都翻转之后,s1变成了"dcba",s2变成了"dc",然后就按照扩展kmp的方法求出s2的每一个后缀在s1中的出现的位置,样例二,s1="abababab", s2="aba".翻转之后s1="babababa",s2="aba"。然后扩展kmp求出extend数组之后, 0 3 0 3 0 3 0 1,然后3代表的s2的前3个字符是和s1相同的,那么前两个也是相同的,前一个也是相同的,所以打个桶记录前缀和就能表示出所有的满足情况了。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<iomanip> 4 #include<stdio.h> 5 #include<cmath> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<cstring> 10 #include<vector> 11 using namespace std; 12 # define ll long long 13 const int mod = 1e9+7; 14 const int maxn = 1e6+100; 15 char str1[maxn]; 16 char str2[maxn]; 17 int nex[maxn],extend[maxn]; 18 ll vis[maxn];
// 注意vis开long long ,否则会爆精度。
// str2是需要匹配的串,str1是被匹配的串。 19 void getnex(int len) 20 { 21 int a=0,p=0; 22 nex[0]=len; 23 for(int i=1; i<len; i++) 24 { 25 if(i>=p||i+nex[i-a]>=p) 26 { 27 if(i>=p) 28 p=i; 29 while(p<len&&str2[p]==str2[p-i]) 30 p++; 31 nex[i]=p-i; 32 a=i; 33 } 34 else 35 nex[i]=nex[i-a]; 36 } 37 } 38 void exkmp(int len1,int len2) 39 { 40 getnex(len2); 41 int a=0,p=0; 42 for(int i=0; i<len1; i++) 43 { 44 if(i>=p||i+nex[i-a]>=p) 45 { 46 if(i>=p) 47 p=i; 48 while(p<len1&&p-i<len2&&str1[p]==str2[p-i]) 49 p++; 50 extend[i]=p-i; 51 a=i; 52 } 53 else 54 extend[i]=nex[i-a]; 55 } 56 } 57 int main() 58 { 59 int T; 60 scanf("%d",&T); 61 while(T--) 62 { 63 memset(vis,0,sizeof(vis)); 64 scanf("%s",str1); 65 scanf("%s",str2); 66 int len1=strlen(str1); 67 int len2=strlen(str2); 68 reverse(str1,str1+len1); 69 reverse(str2,str2+len2); 70 exkmp(len1,len2); 71 for(int i=0;i<len1;i++){ 72 vis[extend[i]]++; 73 } 74 ll ans=len2*vis[len2]%mod; 75 for(int i=len2;i>=2;i--){ 76 vis[i-1]+=vis[i]; 77 ans=(ans+vis[i-1]*(i-1)%mod+mod)%mod; 78 } 79 printf("%lld ",ans); 80 } 81 return 0; 82 }