zoukankan      html  css  js  c++  java
  • 回文自动机学习笔记

    回文自动机学习笔记

    和AC自动机差不多,回文自动机每个节点的含义表示在它的父节点两侧各加上一个儿子字符。并且我们也要维护一个fail指针表示这个节点的最长回文后缀

    PAM有两个根,奇根和偶根,

    偶根的节点编号为 (0),所代表的回文串的长度为 (0),fail指针指向奇根

    奇根的节点编号为 (1),所代表的回文串的长度为 (-1),fail指针指向自身

    fail指针

    fail指针表示这个节点的最长回文后缀,构建方法是往上跳fail直到两端能+1。

    关于新建节点,也是往上跳fail,没有出边就新建点,并且新节点长度等于这个节点长度+2。

    #include<bits/stdc++.h>
    #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
    #define ROF(i,a,b) for(int i=(a);i>=(b);--i) 
    const int inf = 1e9;
    using namespace std;
    int read(){
    	int x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x; 
    }
    const int N = 1e6+200;
    char s[N];
    	int tot,las;
    	int fail[N],len[N],pos[N];
    	int ch[N][26],num[N];
    	void init(){
    		las=0,tot=1;
    		len[0]=0,fail[0]=1;
    		len[1]=-1,fail[1]=0;
    	}
    	void add(int c,int id){
    		int p=las;
    		for(;s[id]!=s[id-len[p]-1];p=fail[p]);
    		
    		if(!ch[p][c]){
    			int np=++tot,q=fail[p];len[np]=len[p]+2;
    			for(;s[id]!=s[id-len[q]-1];q=fail[q]);
    			fail[np]=ch[q][c]; ch[p][c]=np;
    			num[np]=num[fail[np]]+1;
    		}
    		las=ch[p][c]; 
    	}
    int main(){
    	scanf("%s",s+1);
    	init();
    	int pre=0,l=strlen(s+1);
    		FOR(i,1,l){
    			s[i] = (s[i] - 97 + pre) % 26 + 97; 
    			add(s[i]-'a',i);
    			pos[i]=las;
    			printf("%d ",num[las]);
    			pre=num[las];
    		}
    	return 0;
    }
    
  • 相关阅读:
    leetcode 1140. Stone Game II
    主席树
    Codeforces Round #442 (Div. 2) E Danil and a Part-time Job (dfs序加上一个线段树区间修改查询)
    UVALive 3942 Remember the Word
    UVA 11235 Frequent values (RMQ )
    CodeForces
    hdu 2955 Robberies (01背包好题)
    hdu 1054 Strategic Game (简单树形DP)
    hdu 5532 Almost Sorted Array (水题)
    hdu 2089 不要62 (数位dp基础题)
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/13187974.html
Copyright © 2011-2022 走看看