回文树
求0->i内所有的本质不同的回文串的个数, 在 if(!next[cur][ch]) 成立,那么说明出现本质不同的字符串
求每一个本质不同的回文串出现的个数,每个结点都是本质不同的字符串, cnt记录的就是了
求s内回文串的个数,所有的cnt加起来就是了。
求以i结尾的回文串的个数。 num函数就是了。
1 struct PTtree 2 { 3 int next[N][M]; 4 int fail[N]; 5 int len[N];//len[i]表示结点i表示的回文串的长度 6 int cnt[N]; 7 int num[N];//num[i]存放以i结尾的回文串的个数 8 int S[N]; 9 int last,n,p; 10 int newNode(int length) 11 { 12 for(int i=0;i<M; ++i) next[p][i] = 0; 13 num[p] = 0; 14 cnt[p] = 0; 15 len[p] = length; 16 return p++; 17 } 18 void init() 19 { 20 p = 0; 21 newNode(0); 22 newNode(-1); 23 last = 0; 24 n = 0; 25 S[n] = -1; 26 fail[0] = 1; 27 fail[1] = 0; 28 } 29 30 int getFail(int cur) 31 {//如果S[n-len[x]-1]==S[n]那么说明结点x添加新字符后,前面也有一个字符与x相同 32 while(S[n-len[cur]-1] != S[n]) 33 cur = fail[cur];//跳到更短一点的回文后缀节点 34 return cur; 35 } 36 void add(int ch) 37 { 38 ch -= 'a'; 39 S[++n] = ch; 40 int cur = getFail(last); 41 if(!next[cur][ch])//这个回文串没有出现过 42 { 43 ans++; 44 int now = newNode(len[cur]+2); 45 fail[now] = next[getFail(fail[cur])][ch]; 46 next[cur][ch] = now; 47 num[now] = num[fail[now]] + 1;//+1是为当前的回文串,num[fail[now]] 48 //是更短的回文后缀的个数,与字典树的统计是一样的 49 } 50 last = next[cur][ch]; 51 cnt[last]++; 52 } 53 void count() 54 { 55 //逆向是为了避免重复计算 56 for(int i=p-1;i>=0;--i)cnt[fail[i]] += cnt[i];//fail[i]是i是后缀,所以i肯定保护fail[i] 57 } 58 };