您的位置:首页 > 理论基础 > 计算机网络

ccpc 2017 网络赛 1004 A Secret (扩展kmp)【模板】

2017-08-20 17:08 621 查看
Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,which have a big secret.SF is interested in this secret and ask VS how to get it.There are the things that VS tell: 

  Suffix(S2,i) = S2[i...len].Ni is the times that Suffix(S2,i) occurs in S1 and Li is the length of Suffix(S2,i).Then the secret is the sum of the product of Ni and Li. 

  Now SF wants you to help him find the secret.The answer may be very large, so the answer should mod 1000000007.

InputInput contains multiple cases. 

  The first line contains an integer T,the number of cases.Then following T cases.

  Each test case contains two lines.The first line contains a string S1.The second line contains a string S2. 

  1<=T<=10.1<=|S1|,|S2|<=1e6.S1 and S2 only consist of lowercase ,uppercase letter.
OutputFor each test case,output a single line containing a integer,the answer of test case. 

  The answer may be very large, so the answer should mod 1e9+7.
Sample Input
2
aaaaa
aa
abababab
aba


Sample Output
13
19


Hint
case 2:
Suffix(S2,1) = "aba",
Suffix(S2,2) = "ba",
Suffix(S2,3) = "a".
N1 = 3,
N2 = 3,
N3 = 4.
L1 = 3,
L2 = 2,
L3 = 1.
ans = (3*3+3*2+4*1)%1000000007.


 【题解】

  kmp题,,刚开始看成AC自动机了 ,,搞了半天一直哇,,后来换KMP就过了,,这读题真是,,

  就是求一个一个序列的前缀出现次数与其长度乘积的和,扩展kmp做法。

 【AC代码】

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int inf=1e9+7;
int next_t
,extend
;
char s1
,s2
;
int m,n;
int len1,len2;

void get_extend() //扩展KMP数组模板
{
int j=0,k=1;
next_t[0]=len2;
while(j+1<len2 && s2[j]==s2[j+1]) j++;
next_t[1]=j;
for(int i=2;i<len2;++i)
{
if(next_t[i-k]+i<next_t[k]+k) next_t[i]=next_t[i-k];
else
{
j=next_t[k]+k-i;
if(j<0) j=0;
while(i+j<len2 && s2[j]==s2[i+j])
j++;
next_t[i]=j;
k=i;
}
}
}

void e_kmp()
{
int j=0,k=0;
while(j<len1 && j<len2 && s1[j]==s2[j]) j++;
extend[0]=j;
for(int i=1;i<len1;++i)
{
int pos=extend[k]+k-1;
int l=next_t[i-k];
if(i+l<pos+1) extend[i]=l;
else
{
j=max(0,pos-i+1);
while(i+j<len1 && j<len2 && s1[i+j]==s2[j]) j++;
extend[i]=j;
k=i;
}
}
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",s1,s2);
len1=strlen(s1);
len2=strlen(s2);
reverse(s1,s1+len1);
reverse(s2,s2+len2);
get_extend();
ll ans=0;
e_kmp();
for(int i=0;i<len1;++i)
{
ans=(ans+((ll)extend[i]*(extend[i]+1)/2)%inf)%inf;
}
printf("%lld\n",ans);
}
return 0;
}


还有简洁一点的:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf=1e9+7;
const int N=1000005;
char s1
,s2
;
ll sum
;
int next_t
;
int len1,len2;

void get_next()//next数组模板
{
int i=0,j=-1;
next_t[0]=-1;
while(i<len2)
{
while(j!=-1 && s2[i]!=s2[j])
j=next_t[j];
i++;
j++;
next_t[i]=j;
}
}

void e_kmp()
{
int i=0,j=0;
memset(sum,0,sizeof(sum));
while(i<len1)
{
if(j==-1||s1[i] == s2[j]) i++,j++;
else j=next_t[j];
sum[j]++;
if(j==len2)  j=next_t[j];
}
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",s1,s2);
len1=strlen(s1);
len2=strlen(s2);
reverse(s1,s1+len1);
reverse(s2,s2+len2);
get_next();
e_kmp();
ll ans=0;
for(int i=len2;i>0;--i)
{
sum[next_t[i]]+=sum[i];
ans=(ans+sum[i]*i)%inf;
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: