正题
评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P2375
题目大意
对于kmp操作,我们多求一个 数组,表示对于字符串 的前 个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠。
解题思路
我们可以在求next的时候进行递推,然后就可以求出可以重合的num。
然后我们在用next去掉不可以的答案。
但是如果这样我们就会超时,所以我们发现如果不重合,那么长度最大为
,所以我们直接不更新
,因为这个位置满足长度为
,那么也一定满足长度为
的情况。
code
#include<cstdio>
#include<cstring>
#define mod 1000000007
using namespace std;
char s[1000011];
int l,p[1000011],ans[1000001],tot,t;
void ycl()//求next数组
{
ans[0]=0;ans[1]=1;
for (int i=1,j=0;i<l;i++)
{
while (j&&s[i]!=s[j]) j=p[j];
if (s[i]==s[j]) j++;
ans[i+1]=ans[j]+1;//递推
p[i+1]=j;
}
}
long long answer()
{
long long sum=1;
for (int i=1,j=0;i<l;i++)
{
while (j&&s[i]!=s[j]) j=p[j];
if (s[i]==s[j]) j++;
while((j<<1)>(i+1)) j=p[j];//计算j位置
sum=(sum*(long long)(ans[j]+1))%mod;
}
return sum;
}
int main()
{
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
memset(p,0,sizeof(p));
scanf("%s",s);
l=strlen(s);
ycl();
printf("%lld\n",answer());
}
}