ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

字符串

2021-10-08 18:33:26  阅读:189  来源: 互联网

标签:AC int hw mid fail 字符串 自动机


字符串已经忘光了,只好花了一天时间来复习


KMP

一篇好的讲解

KMP模板

code:

#include<bits/stdc++.h>
using namespace std;
string s,t;
int n,m;
int nxt[1000006];
void getnxt(){
	nxt[0]=-1;int i=0,j=-1;
	while(i<m){
		if(j==-1||t[i]==t[j])
			i++,j++,nxt[i]=j;
		else j=nxt[j];
	}
}
void match(){
	int j=0;
	for(int i=0;i<n;i++){
		while(s[i]!=t[j]&&j!=-1)j=nxt[j];
		j++;if(j==m)cout<<i-m+2<<'\n';
	}
}
signed main(){
	cin>>s>>t;n=s.length(),m=t.length();
	getnxt();
	match();
	for(int i=1;i<=m;i++)
		cout<<nxt[i]<<" ";	
	return 0;
}

AC自动机

trie树上的KMP

将多个模式串上trie树,一个文本串来匹配模式串。

fail 类似于 KMP 的 nxt

概括 AC自动机 求 fail 的过程:

1.对整个字典树进行宽度优先遍历。
2.若当前搜索到点 \(x\),那么对于 \(x\) 的第 \(i\) 个儿子(也就是代表字符 \(i\) 的儿子),一直往 \(x\) 的 fail 跳,直到跳到某个点也有 \(i\) 这个儿子,\(x\) 的第 \(i\) 个儿子的 fail 就指向这个点的儿子 \(i\)。

形式上,AC 自动机基于由若干模式串构成的 Trie 树,并在此之上增加了一些 fail 边;本质上,AC 自动机是一个关于若干模式串的 DFA(确定有限状态自动机),接受且仅接受以某一个模式串作为后缀的字符串。

并且,与一般自动机不同的,AC 自动机还有 关于某个模式串的接受状态,也就是与某个模式串匹配(以某个模式串为后缀)的那些状态,即某个模式串在 Trie 树上的终止节点在 fail 树上的整个子树。

AC自动机模板

code:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
char s[N*10];
int c[N][26],tot,b[N],fail[N],last[N],n;
int ans[N];
int flag[N];
void insert(int T){
	cin>>s;
	int u=0,len=strlen(s);
	for(int i=0;i<len;i++){
		int t=s[i]-'a';
		if(!c[u][t]) c[u][t]=++tot;
		u=c[u][t];
	}
	if(b[u])flag[T]=b[u];
	else b[u]=T;
}
void getfail(){
	queue<int> q;
	for(int i=0;i<26;i++) if(c[0][i]) q.push(c[0][i]);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=0;i<26;i++){
			int v=c[u][i];
			if(!v){c[u][i]=c[fail[u]][i];continue;}
			q.push(v);fail[v]=c[fail[u]][i];
			last[v]=b[fail[v]]?fail[v]:last[fail[v]];
		}
	}
}
void find(){
	cin>>s;
	int u=0,len=strlen(s);
	for(int i=0;i<len;i++){
		int t=s[i]-'a',temp=0;
		u=c[u][t];
		if(b[u])temp=u;
		else if(last[u])temp=last[u];
		while(temp){
			ans[b[temp]]++;
			temp=last[temp];
		}
	}
}
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++)insert(i);
	getfail();find();	
	for(int i=1;i<=n;i++)cout<<(flag[i]?ans[flag[i]]:ans[i])<<'\n'; 
}
int main(){
	solve();
	return 0;
}

manacher

入门时的博客

注意其中对于 \(hw_i\) 初始化部分,hw[i]=min(hw[(mid<<1)-i],hw[mid]+mid-i);

其中 hw[mid]+mid-i 等价于 maxright-i​ 这实际上是 \(i\) 在 \(mid\) 左边相对应的 \(j\) 所受的限制,因为 \(hw_j\) 可能会超出 \(mid-hw[mid]\) 的范围,所以需要限定最大值。画图之后翻折过去就能理解。

code:

#include<bits/stdc++.h>
using namespace std;
const int N=11000005;
string t="@#";int n;
inline void gett(){
	char c=getchar();
	while(c>'z'||c<'a')c=getchar();
	while(c>='a'&&c<='z')t+=c,t+="#",c=getchar();
	n=t.length();
}
int hw[2*N],mr,mid,ans;
inline void match(){
	for(int i=1;i<n;i++){
		hw[i]=(mr>i)?min(hw[(mid<<1)-i],mr-i):1;
		while(t[i+hw[i]]==t[i-hw[i]])hw[i]++;
		if(i+hw[i]>mr)mr=i+hw[i],mid=i;
		ans=max(ans,hw[i]);
	}
}
int main(){
	gett();
	match();
	cout<<ans-1;
	return 0;
}

后缀数组

不会

标签:AC,int,hw,mid,fail,字符串,自动机
来源: https://www.cnblogs.com/llmmkk/p/15381235.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有