正题
评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P2375
题目大意
对于kmp操作,我们多求一个numnum数组,表示对于字符串SS的前个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠。
解题思路
我们可以在求next的时候进行递推,然后就可以求出可以重合的num。
然后我们在用next去掉不可以的答案。
但是如果这样我们就会超时,所以我们发现如果不重合,那么长度最大为n÷2n÷2,所以我们直接不更新jj,因为这个位置满足长度为,那么也一定满足长度为i+1i+1的情况。
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());}
}