ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

扩展KMP学习小记

2022-07-13 20:31:51  阅读:160  来源: 互联网

标签:匹配 min db ll 扩展 long KMP 小记 define


简介

扩展KMP(又称EXKMP)是干嘛的?

大概目前已知的可以处理一个字符串和每个后缀的LCP长度,或者匹配串和被匹配串的LCP长度。

做法

先以求出一个字符串和自己后缀的LCP为例。

我们从小到大按位处理,如果暴力往后跑匹配是\(O(n^2)\)的,不能通过。

如果我们记录了之前已经匹配好的区间中,右端点最大的区间\([L,R]\)。那么如果这个区间右端点包含了当前要处理的这个点\(i\),那么我们显然可以初始化\(z_i=\min(z_{L-i+1},R-i+1)\)。然后之后暴力匹配并更新\([L,R]\),容易发现每成功暴力匹配一次,\(R+1\),则复杂度为\(O(n)\)。

事实上个人觉得这个思想和manacher特别像。

如果要求匹配串和被匹配串的LCP长度,那么直接将被匹配串接在匹配串后面,加个特殊字符就可以跑了。

板子题的code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (40000000+5)
#define M (6000000+5)
#define K (1500+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,H,F[N],L,R;char s1[N],s2[N],c[N];ll ToT;
int main(){
	freopen("1.in","r",stdin);
	int i,j;scanf("%s%s",s1+1,s2+1);n=strlen(s1+1);m=strlen(s2+1);for(i=1;i<=m;i++) c[++H]=s2[i];c[++H]='#';for(i=1;i<=n;i++) c[++H]=s1[i];
	for(i=2;i<=H;i++){if(R>=i) F[i]=min(F[i-L+1],R-i+1);while(c[i+F[i]]==c[F[i]+1]) F[i]++;i+F[i]-1>R&&(L=i,R=i+F[i]-1);}F[1]=m;
	for(i=1;i<=m;i++) ToT^=1ll*i*(F[i]+1);printf("%lld\n",ToT);ToT=0;for(i=m+2;i<=H;i++) ToT^=1ll*(i-m-1)*(F[i]+1);printf("%lld\n",ToT); 
}

例题:[NOIP2020] 字符串匹配

这看上去是唯一能找到的例题。

首先我们有一个暴力\(O(n(\ln n+26))\)的东西,枚举\(AB\)串长度,然后往上倍增枚举循环到哪里,哈希判断即可。然后暴力前缀和数点。

首先我们先考虑去掉这个\(O(26n)\)。

设循环节长度为\(Len\),当前循环次数为\(k\),若\(2\mid k\),则\(C\)中奇数字符出现次数等于原串奇数字符出现次数,可以直接维护。

若\(2\nmid k\),则\(C\)中奇数字符出现次数等于\([Len+1,n]\)奇数字符出现次数,因为每次变化量\(O(1)\),故可以\(O(n)\)维护出来。

然后我们现在的问题是:每个位置开始往后能循环几次。

我们考虑对原串跑一边EXKMP,则对于一个位置\(i\),\([1,i-1]\)的循环次数显然为\(\frac{z_i}{i-1}+1\),也可以做到\(O(1)\)。

因此我们可以在\(O(Tn)\)复杂度内解决这个问题。

code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N ((1<<20)+5)
#define M (6000000+5)
#define K (1500+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int T,n,x,y,z,F[N],L,R,Pf[150],Ps,Fl[150],G[150],Fs,P1,P2,Pt,Ct;ll ToT;char A[N];
I void Solve(){
	Me(F,0);Me(G,0);Me(Fl,0);Me(Pf,0);Ct=0;int i;scanf("%s",A+1);n=strlen(A+1);L=R=0;for(i=2;i<=n;i++) {if(i<=R) F[i]=min(F[i-L+1],R-i+1);while(A[i+F[i]]==A[F[i]+1]) F[i]++;if(i+F[i]-1>R) L=i,R=i+F[i]-1;}
	for(i=1;i<=n;i++) Pf[A[i]]^=1;for(i='a';i<='z';i++) Ct+=Pf[i];Ps=Ct;Me(Fl,0);P1=P2=ToT=Fs=0;for(i=2;i<=n;i++){
		Pf[A[i-1]]^=1;Pf[A[i-1]]?(Ps++,P2+=G[Ps]):(P2-=G[Ps],Ps--);if(i>2)x=min(F[i]+i-1,n-1)/(i-1),ToT+=1ll*(x+1)/2*P2+x/2*P1;Fl[A[i-1]]^=1;Fl[A[i-1]]?Fs++:Fs--;G[Fs]++;P1+=(Fs<=Ct);P2+=(Fs<=Ps);
	}printf("%lld\n",ToT);
}
int main(){
	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--) Solve();
}

标签:匹配,min,db,ll,扩展,long,KMP,小记,define
来源: https://www.cnblogs.com/275307894a/p/16475477.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有