A - A Secret (扩展kmp)

题目链接: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\n",ans); 80 } 81 return 0; 82 }

 

posted @ 2019-02-16 14:29  Let_Life_Stop  阅读(170)  评论(0编辑  收藏  举报