您的位置:首页 > 其它

hdu 6153 A Secret(KMP)

2017-08-22 10:35 417 查看

A Secret

[b]Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 1929    Accepted Submission(s): 707
[/b]

[align=left]Problem Description[/align]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. 
[align=left]Input[/align]Input 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. 
[align=left]Output[/align]For 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.  
[align=left]Sample Input[/align]
2
aaaaa
aa
abababab
aba 
[align=left]Sample Output[/align]
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.
 题意:给你一个被匹配串和模式串,要求你每一次求出模式串中sum(每一个后缀的在被匹配串中出现的次数*后缀的长度)
解析:分别将两个串逆序(此时后缀就变成前缀),这样就可以用KMP对两个串进行匹配
在匹配中将记录每一个前缀匹配成功的次数(就是该前缀在被匹配串中出现的次数)最后,将记录匹配次数的数组进行从后往前遍历,将最长的与当前字符作为结尾的后缀相同的前缀的ans[]+当前字符的ans
例如
abaccabaaa
abaccaba
逆序后
aaabaccaba
abaccaba
当从后往前遍历时,ans[3('aba')]+=ans[8('abaccaba')]
因为在abccaba中有两个aba,之前匹配时只加了前面的aba
同时最后的'a'也应该加到ans[1('a')]中,但在加aba时,已经加到aba中了,即等遍历到aba时,ans[1]+=aba中的'a'和abaccaba中结尾的'a'
KMP复杂度 O(m+n)
#include<stdio.h>
#include<string.h>

typedef long long int ll;

const int MAXN = 1e6+10;
const int MOD = 1e9+7;

int next[MAXN];
ll ans[MAXN];   //ans[i]表示长度为i的前缀的匹配次数
char S1[MAXN],S2[MAXN];

void makenext(char P[])
{
int m=strlen(P);
next[0]=0;
for(int q=1,k=0;q<m;q++)
{
while(k>0&&P[q]!=P[k])
k=next[k-1];

if(P[q]==P[k])
{
k++;
}
next[q]=k;
}
}

void KMP(char P[],char T[])
{
int n,m;
n=strlen(T);
m=strlen(P);
makenext(P);
for(int i=0,q=0;i<n;i++)
{
while(q>0&&P[q]!=T[i])
q=next[q-1];

if(P[q]==T[i])
{
q++;
/*int tmp=q;
while(tmp>0)
{
ans[tmp]++;
tmp=next[tmp-1];
}*/
ans[q]++;
//ans[next[q-1]]++;
}
/*int tmp=q;
while(tmp>0)
{
ans[tmp]++;
tmp=next[tmp-1];
}*/
}
}

void Reverse(char S[])
{
int len=strlen(S);
if(len%2)
{
for(int i=len/2+1,j=len/2-1;j>=0&&i<len;j--,i++)
{
char tmp;
tmp=S[i];
S[i]=S[j];
S[j]=tmp;
}
}
else
{
for(int i=len/2,j=i-1;j>=0&&i<len;j--,i++)
{
char tmp;
tmp=S[i];
S[i]=S[j];
S[j]=tmp;
}
}
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(ans,0,sizeof(ans));
scanf("%s",S1);
scanf("%s",S2);
Reverse(S1);
Reverse(S2);
KMP(S2,S1);
ll res=0;
for(int i=strlen(S2);i>0;i--)
{
/*while(next[tmp-1])
{
ans[next[tmp-1]]+=ans[i];
tmp=next[tmp-1];
}*/
ans[next[i-1]]+=ans[i];
ll temp=((ll)(ans[i]*i))%MOD;
res=(res+temp)%MOD;
}
printf("%lld\n",res);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM 2017icpc kmp