当前位置: 首页 > article >正文

【学习笔记】exkmp(Z函数)

本文参考洛谷题解:https://www.luogu.com.cn/article/cq4b4e5f
侵删

前言

exkmp 和 kmp 要求的东西比较类似。
exkmp 可以求出 a i . . . n a_{i...n} ai...n b b b 的最长公共前缀。
这玩意也称 z 函数。

算法流程

求解 nxt 数组

定义 n x t i nxt_i nxti ∣ l c p ( b i . . n , b ) ∣ |lcp(b_{i..n},b)| lcp(bi..n,b),也就是 s s s 每一段后缀和自身的最长公共前缀。
例如:
在这里插入图片描述
那这玩意怎么求呢?
假设 n x t 0... x − 1 nxt_{0...x-1} nxt0...x1 已经求出,考虑如何求 n x t x nxt_x nxtx
还记得 M a n a c h e r Manacher Manacher 是怎么做的吗?你要找到最靠右的回文串,然后用它的信息求当前回文半径。
类似的,对于所有的 1 ≤ x < n 1\leq x < n 1x<n 我们要求出 i + n x t i − 1 i+nxt_i-1 i+nxti1 的最大值,记最大值编号为 k k k,记 p = k + n x t k − 1 p=k+nxt_k-1 p=k+nxtk1
为什么不是 0 ≤ x < n 0 \leq x <n 0x<n?因为 n x t 0 nxt_0 nxt0 一定等于 n n n,这样子就没什么意义了。
根据定义,我们可以得到 b 0... n x t k − 1 = = b k . . . p b_{0...nxt_k-1}==b_{k...p} b0...nxtk1==bk...p 。如图,蓝色部分相等:
在这里插入图片描述
于是,我们就可以推出: b x − k . . . n x t k − 1 = b x . . . p b_{x-k...nxt_k-1}=b_{x...p} bxk...nxtk1=bx...p
在这里插入图片描述
我们最终的目的是求出 n x t x nxt_x nxtx x x x 对应的位置是 x − k x-k xk,所以我们要根据 x − k x-k xk 判断 x x x能跳多远。
l = n x t x − k l=nxt_{x-k} l=nxtxk,如果 x − k + l − 1 x-k+l-1 xk+l1 还在绿色区域范围内,也就是 x − k + l − 1 ≤ n x t k − 1 x-k+l-1\leq nxt_k-1 xk+l1nxtk1,那么 b x − k . . . x − k + l − 1 = = b x . . . x + l − 1 b_{x-k...x-k+l-1}==b_{x...x+l-1} bxk...xk+l1==bx...x+l1。如图,灰色部分相等:
在这里插入图片描述
但是如果它超出了绿色部分,超出的部分就不能保证相等了,要暴力匹配。如图:
在这里插入图片描述
这个过程是不是和Manacher一毛一样?

vector<int> getNext(string &s)
{
	vector<int> nxt(s.size());
	int p=0; //furthest position p=k+nxt[k]-1
	int k=1; //furthest position id
	nxt[0]=s.size();
	while(p+1<s.size()&&s[p]==s[p+1])
		p++;
	nxt[1]=p;
	for(int i=2; i<s.size(); i++)
	{
		p=k+nxt[k]-1;
		int l=nxt[i-k]; //if i+l<=p then [i,i+l-1] == [i-k,i-k+l-1]
		if(i+l<=p) 
			nxt[i]=l;
		else
		{
			int j=max(0ll,p-i+1);
			while(i+j<s.size()&&s[i+j]==s[j])
				j++;
			nxt[i]=j;
			k=i;
		}
	}
	return nxt;
}

求解 extend 数组(z函数)

和求解 n x t nxt nxt 数组的过程类似。
在这里插入图片描述

vector<int> getExtend(string &s,string &t,vector<int> &nxt)
{
	int p=0,k=0;
	while(p<s.size()&&p<t.size()&&s[p]==t[p]) 
		p++;
	vector<int> ext(s.size());
	ext[0]=p;
	for(int i=1; i<s.size(); i++)
	{
		p=k+ext[k]-1;
		int l=nxt[i-k];
		if(i+l<=p) 
			ext[i]=l;
		else
		{
			int j=max(0ll,p-i+1);
			while(i+j<s.size()&&j<t.size()&&s[i+j]==t[j])
				j++;
			ext[i]=j;
			k=i;
		}
	}
	return ext;
}

【模板】扩展 KMP/exKMP(Z 函数)

在这里插入图片描述
在这里插入图片描述

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+7,inf=1e18;
vector<int> getNext(string &s)
{
	vector<int> nxt(s.size());
	int p=0; //furthest position p=k+nxt[k]-1
	int k=1; //furthest position id
	nxt[0]=s.size();
	while(p+1<s.size()&&s[p]==s[p+1])
		p++;
	nxt[1]=p;
	for(int i=2; i<s.size(); i++)
	{
		p=k+nxt[k]-1;
		int l=nxt[i-k]; //if i+l<=p then [i,i+l-1] == [i-k,i-k+l-1]
		if(i+l<=p) 
			nxt[i]=l;
		else
		{
			int j=max(0ll,p-i+1);
			while(i+j<s.size()&&s[i+j]==s[j])
				j++;
			nxt[i]=j;
			k=i;
		}
	}
	return nxt;
}
vector<int> getExtend(string &s,string &t,vector<int> &nxt)
{
	int p=0,k=0;
	while(p<s.size()&&p<t.size()&&s[p]==t[p]) 
		p++;
	vector<int> ext(s.size());
	ext[0]=p;
	for(int i=1; i<s.size(); i++)
	{
		p=k+ext[k]-1;
		int l=nxt[i-k];
		if(i+l<=p) 
			ext[i]=l;
		else
		{
			int j=max(0ll,p-i+1);
			while(i+j<s.size()&&j<t.size()&&s[i+j]==t[j])
				j++;
			ext[i]=j;
			k=i;
		}
	}
	return ext;
}
void O_o()
{
	string s,t;
	cin>>s>>t;
	auto nxt=getNext(t);
	auto ext=getExtend(s,t,nxt);
	int a=0,b=0;
	for(int i=0; i<nxt.size(); i++)
	{
		a^=(i+1)*(nxt[i]+1);
	}
	for(int i=0; i<ext.size(); i++)
	{
		b^=(i+1)*(ext[i]+1);
	}
	cout<<a<<"\n"<<b<<"\n";
}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cout<<fixed<<setprecision(12);
	int T=1;
//	cin>>T
	while(T--)
	{
		O_o();
	}
}

















http://www.kler.cn/a/317933.html

相关文章:

  • uni-app表格带分页,后端处理过每页显示多少条
  • 使用Element UI实现前端分页,及el-table表格跨页选择数据,切换分页保留分页数据,限制多选数量
  • Python 中.title()函数和.lower()函数
  • 【go从零单排】JSON序列化和反序列化
  • Vector Optimization – Stride
  • JFROG相关API
  • 关于C++的备忘录
  • Qt-QComboBox输入类控件(31)
  • 说一说Zookeeper的应用场景及其原理
  • pandas中数据的合并
  • 200Kg大载重多旋翼无人机应用前景详解
  • Solidity——抽象合约和接口详解
  • 【路径规划】 通过使用前向动态规划算法在地形上找到最优路径
  • 运维工程师面试整理-沟通能力
  • Spring Security 详解:保护Java应用的强大盾牌
  • linux下不同库出现符号冲突的解决方式
  • LLM - 理解 多模态大语言模型(MLLM) 的 幻觉(Hallucination) 与相关技术 (七)
  • Jenkins基于tag的构建
  • Redis: 特色,业务场景举例,底层原理,持续进阶等问题梳理
  • 基于C#+SQL Server(CS界面)学生选课及成绩查询管理系统
  • sql语法学习:关键点和详细解释
  • 软件开发人员利用Mendix推动GenAI战略
  • Frontiers出版社系列SCISSCI合集
  • Nginx配置负载均衡
  • 2024全国研究生数学建模竞赛(数学建模研赛)ABCDEF题深度建模+全解全析+完整文章
  • 机器翻译之多头注意力(MultiAttentionn)在Seq2Seq的应用