首页 > 其他分享 >ExKMP Z函数

ExKMP Z函数

时间:2025-01-22 11:20:58浏览次数:1  
标签:ExKMP typedef 函数 int ll define zbox size

更新日志 20250122:开工。

思路

我们定义 \(z_i\) 表示从 \(i\) 开始的后缀整个字符串最长公共前缀长度

考虑它的作用,假如我们要字符串匹配,将模式串接在前面并以特殊字符分隔,然后 \(O(n)\) 遍历原串,当 \(z_i=|T|\)(\(T\) 为模式串)时,这个位置就是一个匹配上的位置的开始。

然后我们考虑如何快速求出 \(z\)。

我们考虑储存最大的 \(i+z_i\) 信息,称作 \(zbox\),也就是匹配上的最大右边界。比如:
image
假如这一段(右侧,左边的是与其相同部分)就是 \(zbox\)。

下面我们考虑 \(i\),也就是当前需要的。

如果 \(i\) 位于 \(zbox\) 内(在 \(zbox\) 外暴力即可),那我们可以找出其在左侧的对应位置。
image

如果对应位置的 \(z\) 在对应的 \(r\) 以内(相等不算),那么显然 \(z_i=z_j\)(\(j\) 为对应位置),因为下一位是相等的,上一段不行,这一段一样的不行。

不然,下一位就是不相等的,就得暴力了。但是,我们可以把 \(zbox\) 以内的部分直接 \(O(1)\) 加过来。

更新 \(zbox\) 部分就不说了,判右边界即可。

这样不难发现每个点只会被暴力一次,复杂度 \(O(n)\)。

模板

string a,b;
int z[N],l,r;
void getz(string s){
	z[0]=l=r=0;
	repl(i,1,s.size()){
		if(i<=r&&z[i-l]<r-i+1)z[i]=z[i-l];
		else{
			z[i]=max(0,r-i+1);
			while(i+z[i]<s.size()&&s[i+z[i]]==s[z[i]])z[i]++;
		}
		if(i+z[i]-1>r)l=i,r=i+z[i]-1;
	}
}

例题

LG5410

代码
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef double db;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
template <typename Type>
using vec=vector<Type>;
template <typename Type>
using grheap=priority_queue<Type>;
template <typename Type>
using lrheap=priority_queue<Type,vector<Type>,greater<Type> >;
#define fir first
#define sec second
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define chmax(a,b) a=max(a,b)
#define chmin(a,b) a=min(a,b)
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define repl(i,x,y) for(int i=(x);i<(y);i++)
#define per(i,x,y) for(int i=(x);i>=(y);i--)

const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;

const int N=4e7+5;

string a,b;
int z[N],l,r;
void getz(string s){
	z[0]=l=r=0;
	repl(i,1,s.size()){
        if(i<=r&&z[i-l]<r-i+1)z[i]=z[i-l];
        else{
            z[i]=max(0,r-i+1);
            while(i+z[i]<s.size()&&s[i+z[i]]==s[z[i]])z[i]++;
        }
        if(i+z[i]-1>r)l=i,r=i+z[i]-1;
    }
}

ll ans1,ans2;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>a>>b;
	a=b+' '+a;
	getz(a);
	z[0]=b.size();
	repl(i,0,b.size())ans1^=((ll)(i+1)*(z[i]+1));
	repl(i,b.size()+1,a.size())ans2^=((ll)(i-b.size())*(z[i]+1));
	cout<<ans1<<"\n"<<ans2;
	return 0;
}

标签:ExKMP,typedef,函数,int,ll,define,zbox,size
From: https://www.cnblogs.com/HarlemBlog/p/18685351

相关文章

  • 函数递归的介绍
    1.递归的定义在C语言中,递归就是函数自己调用自己上面的代码就是main函数在函数主体内自己调用自己但是,上面的代码存在问题:main函数反复地自己调用自己,不受限制,停不下来。最终形成死递归,导致栈溢出1.0栈溢出 每一次函数调用,都要从内存上的栈区为这次函数调用分配......
  • 模拟实现库函数strcat、strcmp
    strcat:字符串追加模拟实现strcat#include<stdio.h>#include<assert.h>char*my_strcat(char*dest,constchar*src){ assert(dest); assert(src); char*ret=dest;//记录起始地址//1.找到目标空间的末尾,即'\0' while(*dest!='\0') { de......
  • 模拟实现库函数strlen
    strlen统计字符串中‘\0’前面出现的字符个数(不包含‘\0’)返回类型:size_t,其实就是unsignedint,即无符号整型方法一:计数器#include<stdio.h>#include<assert.h>size_tmy_strlen(constchar*str){ size_tcount=0; assert(str); while(*str!='\0') { count......
  • SAP MD04对应函数MD_STOCK_REQUIREMENTS_LIST_API解析
    【SAP系统PP模块研究】一、MD04-库存/需求清单简介MD04是SAP系统MRP功能中的重要程序,可以实时按物料查询当前的库存、需求及供给等各元素等信息。点击“MRP元素数据”中的单号,还可进行向上追溯、向下展开等查询,并可跳转到单据的显示、修改界面,还能跳转到后续操作。例如计划......
  • C语言的那点事第五篇:编程界的“外卖小哥”函数
    函数就像是编程界的“外卖小哥”,帮你把任务分解成小块,然后把结果送回来。别担心,我会用幽默的方式带你飞驰在这个奇妙的世界里。咱们开始吧!1.函数定义与调用外卖小哥的职责:想象一下,你每天都要做饭,但每次都从头开始,那得多累啊!函数就像是你的“外卖小哥”,帮你把任务分解成小......
  • 文心快码“函数拆分”功能,遇到复杂程序也不怕!
    ......
  • C++ 如何讲隐藏的函数释放出来
    如果有一个基类:classDog{public: virtual~Dog(){} voidshow(inta) { cout<<"我是一只狗!"<<a<<"岁"<<'\n'; } voidmysong() { cout<<"哈哈哈..."<<'\n'; }privat......
  • 常见数论函数及狄利克雷卷积与莫比乌斯反演 学习笔记
    \(常见数论函数及狄利克雷卷积与莫比乌斯反演学习笔记\)数论函数数论函数指的是定义域为正整数的函数,可以视作一个数列。积性函数与完全积性函数在数论中,若函数\(f(n)\)满足\(f(1)=1\),且\(f(xy)=f(x)f(y)\)对任意互质的\(x,y\in\mathbf{N}^*\)都成立,则\(f(n)\)为......
  • over() (分析函数)
    目录演示数据rank()/dense_rank()示例根据salary排序,跳过同级根据salary排序,不跳过同级min()/max()示例取每个team中salary最大的取每个team中salary最小的lead()/lag()示例查询salary与比自己高一位、低一位的salary的差额first_value()/last_value()示例row_num......
  • vue3 setup函数 有哪些参数,props、{attrs,slots,emit}等
    在Vue3中,setup函数是CompositionAPI的入口点,用于替代传统的data、methods、computed等选项。setup函数可以接收两个参数:props和context。下面详细解释这两个参数及其用途。setup函数签名import{SetupContext}from'vue';exportdefault{props:{//......