exkmp/Z函数

扩展 KMP/exKMP(Z 函数)

首先我们求出 ne 数组。代表 bb 的每一个后缀的最长公共前缀长度。

我们设当前要求 nex,且 k 为使得 p=k+nek1 最大的位置且 0k<x,同时 pk+nek1

于是我们得到了两个蓝块相同。

image

再通过这个图,得出两个绿块相等。接下来我们设 lnexk

这里由于 nexk 的定义,最前面两个灰块一定相等。又因为两个绿块相等,且后两个灰块都是绿块的前缀,所以后两个灰块相等,所以所有灰块相等。

x+lp 时也就是上图的情况,此时的 nex=l,因为 nexk 已经达到了最大。

x+l>p 时,考虑能够判定相等的部分(绿块)已经被全部包含,所以考虑绿块后面的部分即可。发现没有更好的办法,于是我们直接暴力匹配。

由于暴力匹配每次会右移绿块右边界,而显然最多右移 n 次,于是这样是线性的。

所以从 px+1p+1 开始暴力匹配即可。

第二个数组自行类比 ne 数组的求法即可。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 20000005
using namespace std;
int n,m,z[N],p[N];
char a[N],b[N];
void Z(char s[N],int n){
	z[1]=n;
	int l=0,r=0;
	for(int i=2;i<=n;i++){
		if(i<=r)z[i]=min(z[i-l+1],r-i+1);
		while(i+z[i]<=n&&s[i+z[i]]==s[z[i]+1])z[i]++;
		if(i+z[i]-1>r){
			l=i;
			r=i+z[i]-1;
		}
	}
}
void exkmp(char s[N],int n,char t[N],int m){
	Z(t,m);
	int l=0,r=0;
	for(int i=1;i<=n;i++){
		if(i<=r)p[i]=min(z[i-l+1],r-i+1);
		while(i+p[i]<=n&&s[i+p[i]]==t[p[i]+1])p[i]++;
		if(i+p[i]-1>r){
			l=i;
			r=i+p[i]-1;
		}
	}
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
	cin>>a+1>>b+1;
	n=strlen(a+1);
	m=strlen(b+1);
	exkmp(a,n,b,m);
	int res=0;
	for(int i=1;i<=m;i++){
		res^=(i*(z[i]+1));
	}
	cout<<res<<'\n';
	res=0;
	for(int i=1;i<=n;i++){
		res^=(i*(p[i]+1));
	}
	cout<<res<<'\n';
	return 0;
}
posted @   zxh923  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示