YBTOJ:前缀数组(KMP)

本文探讨了一种利用KMP算法思想解决字符串处理问题的方法,通过预处理失配指针来优化搜索效率。作者在尝试解决一个字符串匹配问题时,最初采用暴力方法遇到性能瓶颈,随后转向倍增技巧,但仍然无法通过所有测试用例。最终,作者发现了可以在O(n)时间内维护失配指针的正确算法,并提供了相应的代码实现。文章强调了证明算法正确性的重要性,并鼓励读者深入思考。
摘要由CSDN通过智能技术生成

题目描述

请添加图片描述

解析

题面脸上写着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
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值