别人的回文自动机
Posted profish
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了别人的回文自动机相关的知识,希望对你有一定的参考价值。
#include<bits/stdc++.h> //CLOCKS_PER_SEC #define se second #define fi first #define ll long long #define Pii pair<int,int> #define Pli pair<ll,int> #define ull unsigned long long #define ALL(x) x.begin(),x.end() #define pb push_back //#define mp make_pair #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) const int maxn=3e5+10; const int inf=0x3f3f3f3f; const int mod=1e9+7; using namespace std; typedef double db; const db eps=1e-10; const db pi=acos(-1); const int MAXN=300005; const int N=26; int ans[maxn],p[maxn*2]; char s[maxn]; void Manacher(char *s,int n,int *pa) pa[0] = 1; for(int i=1,j=0;i<(n<<1)-1;++i) int p = i >> 1 , q = i - p , r = ((j + 1)>>1) + pa[j] - 1; pa[i] = r < q ? 0 : min(r - q + 1 , pa[(j<<1) - i]); while(0 <= p - pa[i] && q + pa[i] < n && s[p - pa[i]] == s[q + pa[i]]) pa[i]++; if(q + pa[i] - 1 > r) j = i; inline bool check(int L,int R) int mid=L+R>>1; if ((L&1)==(R&1)) return p[mid<<1]>=R-L+2>>1; return p[mid<<1|1]>=R-L+1>>1; inline bool Check(int L,int R) int mid=L+R>>1; if (!check(L,mid) || !check(mid+((L&1)!=(R&1)),R)) return false; return true; struct Palindromic_Tree int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成 int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点 int cnt[MAXN]; int num[MAXN]; int len[MAXN];//len[i]表示节点i表示的回文串的长度 int S[MAXN];//存放添加的字符 int last;//指向上一个字符所在的节点,方便下一次add int n;//字符数组指针 int p;//节点指针 int newnode(int l)//新建节点 for(int i=0;i<N;++i) next[p][i]=0; cnt[p]=0; num[p]=0; len[p]=l; return p++; void init()//初始化 p=0; newnode(0); newnode(-1); last=0; n=0; S[n]=-1;//开头放一个字符集中没有的字符,减少特判 fail[0]=1; int get_fail(int x)//和KMP一样,失配后找一个尽量最长的 while(S[n-len[x]-1]!=S[n]) x=fail[x]; return x; void add(int c) c-=‘a‘; S[++n]=c; int cur=get_fail(last) ;//通过上一个回文串找这个回文串的匹配位置 if(!next[cur][c])//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串 int now=newnode(len[cur]+2) ;//新建节点 fail[now]=next[get_fail(fail[cur])][c] ;//和AC自动机一样建立fail指针,以便失配后跳转 next[cur][c]=now ; last=next[cur][c] ; cnt[last]++; num[last]=n; void count() for(int i=p-1;i>=0;--i) cnt[fail[i]]+=cnt[i]; //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串! void get_ans() for(int i=0;i<p;i++) if(len[i]>0) //cout<<num[i]<<‘ ‘<<len[i]<<‘ ‘<<num[i]-len[i]/2-1<<‘ ‘<<num[i]+len[i]/2-1<<endl; if(Check(num[i]-len[i],num[i]-1)) ans[len[i]]+=cnt[i]; PAM; int main() while(~scanf("%s",&s)) PAM.init(); int l=strlen(s); for(int i=1;i<=l;i++) ans[i]=0; Manacher(s,l,p); for(int i=0;s[i];i++) PAM.add(s[i]); PAM.count(); PAM.get_ans(); for(int i=1;i<=l;i++) printf("%d",ans[i]); if(i!=l) printf(" "); else printf("\n");
以上是关于别人的回文自动机的主要内容,如果未能解决你的问题,请参考以下文章