• 扩展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++; .... 因为这个长度是包含了自己本身的

    模板题:

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

  • 相关阅读:
    Mysql学习笔记(十四)备份与恢复
    Mysql学习笔记(十三)权限管理
    docker容器持久化卷讲解
    logstash关于date时间处理的几种方式总结
    ELK收集tomcat状态日志
    ELK收集tomcat访问日志并存取mysql数据库案例
    利用fpm制作rpm包
    Elasticsearch一些常用操作和一些基础概念
    Linux Cluster
    LNMP下动静分离部署phpmyadmin软件包
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/16472670.html
Copyright © 2020-2023  润新知