题意:
给你一个母串和模板串,求子串所有后缀在母串中出现的次数。求所有后缀的长度乘上次数的和。
思路:
把母串和模板串倒转后,用扩展KMP求母串每个位置与子串的最大前缀,求出每种长度的次数后,其对和的贡献为 (长度i的次数)*(i+1)*i/2 。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod = 1e9+7;
ll ans[maxn];
void getNext(char *mo,int next[])
{
int len = strlen(mo);
next[0] = len;
int i = 0;
while(i+1<len&&mo[i]==mo[i+1])
i++;
next[1] = i;
int po = 1;//po为最远点对应的next点
for(i = 2;i<len;i++)
{
if(next[i-po]+i<next[po]+po)
next[i] = next[i-po];
else
{
int j = next[po]+po-i;//最远处到i的距离
if(j<0)
j = 0;
while(i+j<len&&mo[j]==mo[i+j])
j++;
next[i] = j;
po = i;
}
}
}
void getExtend(char *mu,char *mo,int next[],int ex[])
{
getNext(mo,next);
int len1 = strlen(mu),len2 = strlen(mo);
int i = 0;
while(i<len1&&i<len2&&mu[i]==mo[i])
i++;
ex[0] = i;
int po = 0;
for(i = 1;i<len1;i++)
{
if(next[i-po]+i<ex[po]+po)
ex[i] = next[i-po];
else
{
int j = ex[po]+po-i;
if(j<0)
j = 0;
while(j<len2&&j+i<len1&&mu[j+i]==mo[j])
j++;
ex[i] = j;
po = i;
}
}
}
int main()
{
int t;
char mu[maxn],mo[maxn];
int next[maxn],ex[maxn];
while(~scanf("%d",&t))
{
scanf("%s%s",mu,mo);
int len1 = strlen(mu);
int len2 = strlen(mo);
reverse(mu,mu+len1);
reverse(mo,mo+len2);
getExtend(mu,mo,next,ex);
memset(ans,0,sizeof(ans));
for(int i = 0;i<len1;i++)
{
//cout<<ex[i]<<endl;
ans[ex[i]]++;
}
ll res = 0;
for(int i = 1;i<=len1;i++)
{
res = (res+ans[i]*(i+1)*i/2%mod)%mod;
}
printf("%lld\n",res);
}
return 0;
}