首页 > 其他分享 >回文自动机(PAM)

回文自动机(PAM)

时间:2023-04-16 16:11:23浏览次数:30  
标签:int 奇根 lst fail 自动机 PAM 回文

瞎扯,不做教程。

回文自动机是接受串 \(s\) 所有本质不同回文子串的类自动机结构。

考察该类自动机结构的转移边上字符的含义,因为回文串是回文的,所以从 \(s\) 转移到 \(t\) 应该在 \(s\) 所代表的字符串两边均加上转移边上的字符 \(c\)。

这样就会有一个问题:考虑每次走转移边字符串长度都增加 \(2\),那么奇回文串怎么办?

为了解决这个问题,我们建立奇偶两根,偶根长度为 \(0\),奇根长度为 \(-1\)。这样长度为奇数的回文串都接在奇根下面。

那么 fail 咋整呢?为了方便,我们直接把偶根的 fail 设为奇根,体会一下代码就会发现妙处。接下来我们要插入字符串中的每一个字符,首先记下插入 \(s[1,i-1]\) 后所在节点 \(lst\)(即 \(s[1,i-1]\) 的最长回文后缀),然后考虑从 \(lst\) 开始一直跳 fail,直到 \(lst\) 所对应字符串在原串中的前一个位置和 \(s_i\) 相等,如果 \(lst\) 的 \(s_i\) 出边没有节点,那么就新建一个,否则无事发生。

考虑新建节点的 fail,就是从 \(lst\) 的 fail 开始跳 fail,直到前一个位置和 \(s_i\) 相等即可。

容易证明时间复杂度 \(O(n)\)。

# include <bits/stdc++.h>

const int N=500010,INF=0x3f3f3f3f;

struct pam{
	int ch[26],len,fail;
}tr[N];

int num[N];

char s[N];
int n; 
int cnt,last;

inline int read(void){
	int res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-') f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}
inline int NewNode(int l){
	tr[++cnt].len=l;
	return cnt;
}
inline void init(void){
	cnt=-1,NewNode(0),NewNode(-1),s[0]='#',tr[0].fail=1;
	return;
}
inline int getfail(int x,int clen){
	while(s[clen-1-tr[x].len]!=s[clen]) x=tr[x].fail;
	return x;
}
inline int ins(int x){
	int cur=getfail(last,x),p=-1;
	if(!tr[cur].ch[s[x]-'a']){
		p=NewNode(tr[cur].len+2),tr[p].fail=tr[getfail(tr[cur].fail,x)].ch[s[x]-'a'],tr[cur].ch[s[x]-'a']=p;
		num[p]=num[tr[p].fail]+1;
	}
	last=tr[cur].ch[s[x]-'a'];
	return num[last];
}

int main(void){
	scanf("%s",s+1),n=strlen(s+1);
	init();
	int lst=0;
	for(int i=1;i<=n;++i){
		if(i>=1) s[i]=(s[i]-'a'+lst)%26+'a';
		printf("%d ",lst=ins(i));
	}
	
	return 0;
}

标签:int,奇根,lst,fail,自动机,PAM,回文
From: https://www.cnblogs.com/liuzongxin/p/17323431.html

相关文章

  • 131. 分割回文串
    classSolution{public:boolcheck(strings){intn=s.size();for(inti=0;i<n/2;i++)if(s[i]!=s[n-i-1])returnfalse;returntrue;}vector<vector<string>>res;vecto......
  • 算法-回文链表-24
    /***Definitionforsingly-linkedlist.*publicclassListNode{*publicintval;*publicListNodenext;*publicListNode(intx){val=x;}*}*/publicclassSolution{publicListNodeReverseList(ListNodehead){i......
  • 【学习笔记】后缀自动机 SAM
    由于本人时间原因,此处只为一个SAM的总结,讨论SAM的基本操作以及性质,详细证明如要详细学习请查询luogu题解。算法原理SAM中每一个节点代表所有结束位置(endpos)相同的串的集合。每个节点有:1.后缀链接link(到endpos包含它且maxlen最长的那个点,且是为当前点的后缀的点)2.此点所代表的......
  • 回文方阵
    #include<stdio.h>#include<string.h>#defineMAXN10inta[MAXN][MAXN];intmain(){intn,t=0;while(scanf("%d",&n)!=EOF){memset(a,0,sizeof(a));t=a[0][n-1]=1;inti=0,j=n-1;while(t<n*n)......
  • HDU 2222 Keywords Search (AC自动机)
    题目地址:HDU2222AC自动机第一发!真好奇这些算法是怎么被发明的。。算法的魅力真是无穷。这题是AC自动机模板题。自己实在写不出来,比着kuangbin的模板写的==代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#incl......
  • [C++]LeetCode1147. 段式回文
    [C++]LeetCode1147.段式回文题目描述Difficulty:困难RelatedTopics:贪心,双指针,字符串,动态规划,哈希函数,滚动哈希你会得到一个字符串text。你应该把它分成k个子字符串(subtext1,subtext2,…,subtextk),要求满足:subtexti是非空字符串所有子字符串的连接......
  • P6216 回文匹配
    回文匹配/*这里sum表示一维前缀和sum(r-m+1)-sum(l-1)sum(r-m+1-i)-sum(l-1+i)所以应该是使用二位前缀和来进行处理len/2也就是我半径需要的最小长度有些难模拟,但是就是二维前缀和最后统计答案的地方是真的绕*/#include<bits/stdc++.h>usingnamespacestd;con......
  • 回文树
    具体思想不多说structnode{intson[26];intlen;intfail;}t[N];intcnt=1,last=0;voidinit(){t[0].fail=1;t[1].len=-1;}intgetfail(intp,intr){while(r-t[p].len-1<0||s[r-t[p].len-1]!=s[r])p=t[p].fail;returnp;}intinsert(intx,int......
  • PAT Basic 1079. 延迟的回文数
    PATBasic1079.延迟的回文数1.题目描述:给定一个\(k+1\)位的正整数\(N\),写成\(a_k⋯a_1a_0\)的形式,其中对所有\(i\)有\(0≤a_i<10\)且\(a_k>0\)。\(N\)被称为一个回文数,当且仅当对所有\(i\)有\(a_i=a_{k−i}\)。零也被定义为一个回文数。非回文数也可以通过一......
  • 2217. 找到指定长度的回文数
    题目描述给了一个正整数k,表示长度是k的所有回文数字再给了和很多q,问第q小的数字是多少?f1数学关系+构造基本分析从q之间的相互关系考虑还是单独考虑某个q和结果的关系?后者长度是k的回文数字有啥特性?前一半数字是固定的,half=k+1>>2,str[num][:half]以上性质和q有啥......