文章目录
- 题目描述
- 解析
- 代码
题目描述
解析
题面脸上写着5个大字:我是KMP
但是本题没有自己做出来。。。我一开始的思路其实很接近题解了,只是被我舍弃了qwq。
后来卡在暴力nL2的瓶颈上,用了个倍增的诡异操作搞到了nLlogL,但是n=5,L=1e6还是过不去。。。(我其实觉得1e8能过啊qwq)
接下来讲讲题解思路吧
其实也简单,就是预处理出失配指针后
我们的目标是对每一个i不断令k往前跳失配数组,直到k<=i/2位置(所以我就用倍增了啊awa)
但这个可以用和kmp很类似的办法O(n)维护:
就是:
for(int i=1,j=0;i<=l;i++){while(s[i+1]!=s[j+1]&&j) j=p[j];if(s[i+1]==s[j+1]) j++;while((j<<1)>(i+1)) j=p[j];pl[i]=j;
}
这个其实很容易写,我一开始也写了个很类似的,但是被我否掉了
我觉得j跳失配数组这个行为是不可逆的,但是后来随着i变大j可能不跳失配也可以合法
但这其实是不会发生的
因为如果j一直不跳失配的话,j会和i一起不断变大
不可能变合法的
这样这个算法就是对的了
证明还是看思维的严谨性啊。。。
加油吧
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef unsigned long long ull;
const int N = 1e6+100;
const int M=1e7+5;
const int mod=1e9+7;
int n,m;
int l;
char s[N];
int p[N],num[N];
int pl[N][32],mi[32];
void solve(){p[1]=0;l=strlen(s+1);num[0]=0;num[1]=1;for(int i=1,j=0;i<=l;i++){while(s[i+1]!=s[j+1]&&j) j=p[j];if(s[i+1]==s[j+1]) j++;//while((j<<1)>(i+1)) j=p[j];p[i+1]=j;num[i+1]=num[j]+1;}
}
int main(){scanf("%d",&n);for(int k=1;k<=n;k++){scanf(" %s",s+1);solve();ll ans=1;for(int i=1,j=0;i<=l;i++){while(s[i+1]!=s[j+1]&&j) j=p[j];if(s[i+1]==s[j+1]) j++;while((j<<1)>(i+1)) j=p[j];//p[i+1]=j;ans=(ans*(num[j]+1))%mod;}printf("%lld\n",ans);}return 0;
}
/*
3
abdcdjjjds
ajjsnbadcd
cdjjsdcdda
*/