Manacher-马拉车算法
Manacher
马拉车算法就是求解最长回文串
并且将时间复杂度降到了O(n),
它的原理就是将原始字符串进行了处理,在每一个字符的左右两边都加上特殊字符,让字符串变成一个奇回文
然后通过数组储存标记,详细看这篇https://www.jianshu.com/p/392172762e55
回文自动机
回文树,也叫回文自动机
类似AC自动机的一种回文串匹配自动机,也就是一棵字符树。同样类似AC自动机的是,每一个节点都有一个fail指针,fail指针指向的点表示当前串后缀中的最长回文串。
A - The Number of Palindromes
Now, you are given a string S. We want to know how many distinct substring of S which is palindrome.
InputThe first line of the input contains a single integer T(T<=20), which indicates number of test cases.
Each test case consists of a string S, whose length is less than 100000 and only contains lowercase letters.
OutputFor every test case, you should output "Case #k:" first in a single line, where k indicates the case number and starts at 1. Then output the number of distinct substring of S which is palindrome.
Sample Input
3 aaaa abab abcd
Sample Output
Case #1: 4 Case #2: 4 Case #3: 4
因为回文自动机中每个新建的结点就表示一个回文子串,各个结点都不相同
所以不同回文子串个数就是回文自动机中新增结点个数,直接输出即可
#include<iostream> using namespace std; const int maxn=100010; const int ma=26; typedef long long ll; struct node { int next[maxn][ma];//和字典树的next指针类似 int fail[maxn];//失配后指向fail指针 ll cnt[maxn]; int num[maxn]; int len[maxn];//回文串长度 int s[maxn];//字符 int last; int n,p;//添加的字符个数,节点个数 int newnode(int l) { for(int i=0;i<ma;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 gfail(int x)//找最长 { while(s[n-len[x]-1]!=s[n]) x=fail[x]; return x; } void add(int c) { c-='a'; s[++n]=c; int cu=gfail(last);//找匹配位置 if(!next[cu][c]) { int now=newnode(len[cu]+2);//新建节点 fail[now]=next[gfail(fail[cu])][c]; next[cu][c]=now; num[now] = num[fail[now]] + 1 ;//AC自动化及同款指针 } last=next[cu][c]; cnt[last]++; } void count() { for(int i=p-1;i>=0;i--) cnt[fail[i]]+=cnt[i]; } }tree; int main() { string a; std::ios::sync_with_stdio(false); int t; int m=1; cin>>t; while(t--) { cin>>a; tree.init(); int len=a.size(); for(int i=0;i<len;i++) { tree.add(a[i]); } cout<<"Case #"<<m++<<": "; cout<<tree.p-2<<endl; } return 0; }