扩展kmp

目的: 求字符串a的每一个后缀字串 和 目标串b 的lcp(最长的公共前缀)

核心: DP思想, 更新 i 时 利用已知信息, 阴影 来处理, 在阴影里面 O1get, 阴影外面就更新阴影

思路:

  • 利用 公共部分(跳过)来优化时间复杂度,
  • 2个核心数组 nxt[] (b的lcp),extend(a的lcp)
  • 一个关键元素 po (当前最长位置的开始地方)
  • 利用这个当前最长位置,也就是这个阴影已经覆盖的地方, 在阴影里面就是O1处理, 不然就更新这个阴影, 这个阴影就是N长
  • 时间复杂度就是这个阴影的长度 O(n);  extend[i], 以i为开始和目标串 Lcp的最大匹配数(包含了自己的)
  • nxt, 同理,不过是目标串的.
  • 通过上面这个图更新i时看, 是否他的最大长度在这个阴影里面, 是就 O1处理, >= 就要对未知进行更新, 

代码:

#include <bits/stdc++.h>
using namespace std;
#define ri register int 
#define M 20000007


int n,m;
string s1,s2;
int nxt[M],extend[M];
void getnxt()
{
    int len=s2.length();
    nxt[0]=len;
    int i=0;
    while(s2[i]==s2[i+1]&&i+1<len) i++;nxt[1]=i;
    int po=1;
    for(ri i=2;i<len;i++)
    {
        if(nxt[i-po]+i<nxt[po]+po)
        {
            nxt[i]=nxt[i-po];
        }
        else
        {
            int j=po+nxt[po]-i;
            if(j<0) j=0;
            while(s2[i+j]==s2[j]&&i+j<len) j++;nxt[i]=j;
            po=i;
        }
    }
}
void getextend()
{
    int l1=s1.length(),l2=s2.length();
    int i=0;
    while(s1[i]==s2[i]&&i<l1&&i<l2) i++; extend[0]=i;
    int po=0;
    for(ri i=1;i<l1;i++)
    {
        if(nxt[i-po]+i<po+extend[po])
        {
            extend[i]=nxt[i-po];
        }
        else
        {
            int j=po+extend[po]-i; /// (po+extendp[po]-1-i+1) 
            if(j<0) j=0;
            while(s1[i+j]==s2[j]&&j<l2&&i+j<l1) j++;extend[i]=j;
            po=i;
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    
    cin>>s1>>s2;
    
    getnext();
    
    getextend();
    long long ans=0;
    for(ri i=0;i<s2.length();i++)
    {
        ans^=1ll*(i+1)*(nxt[i]+1);
    }
    cout<<ans<<endl;
    ans=0;
    for(ri i=0;i<s1.length();i++)
    {
        ans^=1ll*(i+1)*(extend[i]+1);
    }
    cout<<ans;
    return 0;
    
}
View Code

 

 

后记:

  • 记得对 po 更新!!
  • 为什么是j++; .... 因为这个长度是包含了自己本身的
  • j=extend[po]-po-i,  就是这样
  • 注意 i 的初始化 从哪里开始

模板题:

P5410 【模板】扩展 KMP(Z 函数) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

posted @ 2022-07-13 09:38  VxiaohuanV  阅读(18)  评论(0编辑  收藏  举报