您的位置:首页 > 其它

hdu 6153 (扩展kmp)

2017-08-23 10:42 447 查看
题意:给定两个字符s1,(length=len1),s2(length=len2);求s2[i->len](i=1,2,3,4,....len),在s1中出现的次数乘上其长度;例如 s1=abababc,s2=abc,则应求abc,bc,c,在s1中出现的次

数。然而扩展kmp是求前缀的,所以想到将s1,s2反转一下,即求cba,cb,c,在cbababa中的出现次数答案与不反转相同(仔细想想就知道),要想求cba,cb,c,在cbababa中的出现

次数,只需求以cbababa为母串,以cba为字串的ex数组因为 cba包括(cb,c),最后每一个不为0的ex[i]利用等差数列求和公式算一遍加到ans中(cba出现一次,也就是3*1,

那么相当于cb出现了一次,即2*1,也相当于c出现一次即1*1,最后总次数加上1+2+3)。

  下面是ac代码,代码中的扩展kmp模板百度到处是,扩展kmp不懂的话推荐百度的刘雅琼老师的ppt。https://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const long long maxn=1e6+5;
const long long mod=1e9+7;
ll ex[maxn],nex[maxn];
char s1[maxn],s2[maxn];
void get_next(char *str)
{
int len,j,i=0,po;
len=nex[0]=strlen(str);
while (str[i]==str[i+1]&&i+1<len)
i++;
nex[1]=i;
po=1;
for (i=2;i<len;i++)
{
if (nex[i-po]+i<nex[po]+po)
nex[i]=nex[i-po];
else
{
j=nex[po]+po-i;
if (j<0) j=0;
while (i+j<len&&str[j]==str[j+i])
j++;
nex[i]=j;
po=i;
}
}
}
void get_extend(char *s1,char *s2)
{
int i=0,j,po,len,l2;
len=strlen(s1);
l2=strlen(s2);
get_next(s2);
while (s1[i]==s2[i]&&i<len&&i<l2)
i++;
ex[0]=i;
po=0;
for (i=1;i<len;i++)
{
if (nex[i-po]+i<ex[po]+po)
ex[i]=nex[i-po];
else
{
j=ex[po]+po-i;
if (j<0) j=0;
while (i+j<len&&s2[j]==s1[i+j]&&j<l2)
j++;
ex[i]=j;
po=i;
}
}
}
int main()
{
int n1,n2,t;
ll ans;
cin>>t;
while (t--)
{
scanf ("%s%s",s1,s2);
ans=0;
n1=strlen(s1);
n2=strlen(s2);
reverse(s1,s1+n1);
reverse(s2,s2+n2);
memset(nex,0,sizeof(nex));
memset(ex,0,sizeof(ex));
get_extend(s1,s2);
for (int i=0;i<n1;i++)
if (ex[i])
ans=(ans+ex[i]*(ex[i]+1)/2)%mod;
cout<<ans<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  扩展kmp