zoukankan      html  css  js  c++  java
  • 扩展 KMP(Z 函数)学习笔记

    前言

    一个很冷门的算法,而且相信要不是它出现在了(NOIP2020T2),它还会继续冷门下去。

    估计以后应该也碰不上这个算法的题目了,所以完全就是为了做一道题学了一个算法。。。

    (Z)函数

    对于一个字符串(s),定义(Z(i))表示(s)(i)个后缀(s)(LCP)长度。

    至于它的求法,个人感觉明明叫(ExKMP)却和(KMP)毫无关系,反而与(Manacher)有着异曲同工之妙。

    考虑从小到大枚举(i),同时维护(Mx)表示已经求解过的位置中最大的(i+Z(i)-1),并记录(id)表示一个能取到最大值的位置。(注意,(id)不能等于(1),因为(Z(1))很特殊,为(n)

    也就是说,我们能够确定([id,Mx])([1,Z(id)])是完全相同的两个子串。

    然后,对于当前的(i),若它大于(Mx),则直接暴力扩展。

    否则,根据已知信息,我们可以得出([i,Mx])([i-id+1,Z(id)])是两个完全相同的子串。

    又已知([i-id+1,(i-id+1)+Z(i-id+1)-1])([1,Z(i-id+1)])是相同的子串。

    因此,经过两次转化,我们得出([i,Mx])([1,min{Z(i-id+1),Mx-i+1}])两个子串是一样的。

    那么我们只要在(min{Z(i-id+1),Mx-i+1})的基础上继续尝试暴力扩展即可。

    复杂度证明的话,可以发现一个位置最多被扩展到一次,因此是(O(n))的。

    扩展(KMP)

    扩展(KMP)就是对于两个字符串(s1,s2),求(s1)的每一个后缀和(s2)(LCP)长度。

    我们先求出(s2)(Z)函数,然后以此去和(s1)匹配。

    仔细想想就会发现这个匹配的过程和前面求(Z)函数的过程是几乎一样的,同样只要暴力扩展就行了,复杂度依然有保证。

    模板(板子题)

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 20000000
    using namespace std;
    int n,m;char s1[N+5],s2[N+5];
    int Z[N+5];I void GetZ()//预处理Z函数
    {
    	RI i,id,Mx=0;for(Z[1]=m,i=2;i<=m;++i)
    	{
    		i<=Mx&&(Z[i]=min(Z[i-id+1],Mx-i+1));//计算Z(i)初始值
    		W(i+Z[i]<=m&&s2[i+Z[i]]==s2[1+Z[i]]) ++Z[i];//暴力扩展
    		i+Z[i]-1>Mx&&(Mx=i+Z[id=i]-1);//尝试更新最右点
    	}
    }
    int p[N+5];I void ExKMP()//扩展KMP,和上面类似
    {
    	RI i,id,Mx=0;for(i=1;i<=n;++i)
    	{
    		i<=Mx&&(p[i]=min(Z[i-id+1],Mx-i+1));
    		W(i+p[i]<=n&&1+p[i]<=m&&s1[i+p[i]]==s2[1+p[i]]) ++p[i];
    		i+p[i]-1>Mx&&(Mx=i+p[id=i]-1);
    	}
    }
    int main()
    {
    	RI i;long long t;scanf("%s%s",s1+1,s2+1),n=strlen(s1+1),m=strlen(s2+1),GetZ(),ExKMP();
    	for(t=0,i=1;i<=m;++i) t^=1LL*i*(Z[i]+1);printf("%lld
    ",t);
    	for(t=0,i=1;i<=n;++i) t^=1LL*i*(p[i]+1);printf("%lld
    ",t);return 0;
    }
    
  • 相关阅读:
    FMDB增删查改
    https相关内容
    支付宝、微信支付参考博客
    下标脚本(Swift)
    函数(swift)
    控制流(swift)
    UIView Methods
    oc js 交互
    我和Lua并非一见钟情,我们期待着日久生情(相遇篇)
    与Python Falling In Love_Python跨台阶(面向对象)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/ExKMP.html
Copyright © 2011-2022 走看看