Orion545
2018-04-21 12:01:41
蒟蒻のblog
鉴于评论区的大家对代码中的
考虑
实际上这些
那么理解了这个以后,就可以轻松意识到,代码里面的
应当意识到,由于对于前缀
在后面的递归求解过程中,如果把这个过程放到
首先,这题最好的一个地方,在于它给出的关于
然后是正文:
这道题的输入有1e6个字符,显然需要
先看到
这说明什么?
说明
而这个和值,是可以推出来的
考虑一个前缀
其中,
那么,我们其实只要在求
还是看上面那张图
首先
也就是说,一旦有一个递归了n层的next,比原前缀i的长度的一半要小,那么这个next的递推出的答案
假如我们拿到的串是1e6个'a',那么上面那个算法就会被卡成
那么我们需要做一个优化,来解决这个问题,而解决问题的核心就是:减少重复递归
减少重复递归......有没有想到什么?
没错,就是如同求
我们将递归用的变量
这时再递归求解,总时间效率是
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll MOD=1e9+7;
int n,fail[1000010],ans[1000010];ll cnt;char a[1000010];
int main(){
int T,i,j;scanf("%d",&T);
while(T--){
scanf("%s",a);n=strlen(a);
memset(fail,0,sizeof(fail));
j=0;ans[0]=0;ans[1]=1;
for(i=1;i<n;i++){//求解next
while(j&&(a[i]!=a[j])) j=fail[j];
j+=(a[i]==a[j]);fail[i+1]=j;ans[i+1]=ans[j]+1;//递推记录ans
}
j=0;cnt=1;
for(i=1;i<n;i++){//求解num
while(j&&(a[i]!=a[j])) j=fail[j];
j+=(a[i]==a[j]);
while((j<<1)>(i+1)) j=fail[j];
cnt=(cnt*(ll)(ans[j]+1))%MOD;//记得+1
}
printf("%lld\n",cnt);
}
}