回文树入门
Posted cgjh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回文树入门相关的知识,希望对你有一定的参考价值。
回文串 HYSBZ - 3676
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
建一颗回文树,然后getans统计答案就OK了. (回文树见IOI2017论文)
#include <cstdio> const int maxn = 300050; class pal { public: int next[maxn][26]; int fail[maxn]; int len[maxn]; int cnt[maxn]; char str[maxn]; int last; int tot; int n; // 记录节点长度,同时返回一个节点 inline int node(int _len) { len[tot] = _len; return tot++; } // odd根初始化为: 长度为-1 even根初始化len为0 // 同时str[0]设置为字符集没有的字符 用于判断. // even根的fail指针是odd根 odd根的fail指针是自身. void init() { last = tot = n = 0; node(0); node(-1); str[0] = -1; fail[0] = fail[1] = 1; } // 获得添加字符后,可以组成回文串的位置. inline int GetFail(int cur) { while (str[n-len[cur]-1] != str[n]) cur = fail[cur]; return cur; } // 添加新字符 void insert(char ch) { str[++n] = ch; int cur = GetFail(last), now; if (!next[cur][ch]) { now = node(len[cur] + 2); fail[now] = next[GetFail(fail[cur])][ch]; //和下一句的顺序不能反 next[cur][ch] = now; } ++cnt[last = next[cur][ch]]; // 出现次数,但是不完全统计,还需要for来统计.(因为一个长的回文串可能会包含一些小的回文串.) } long long getans() { int i; long long res = 0; for (i=tot-1; i; --i) // 统计出现次数 cnt[fail[i]] += cnt[i]; for (i=tot-1; i; --i) if (res < 1ll*len[i]*cnt[i]) res = 1ll*len[i]*cnt[i]; return res; } }pal; char s[300050]; int main() { // freopen("E:\input.txt", "r", stdin); pal.init(); scanf("%s", s); for (char *p=s; *p; p++) pal.insert(*p - ‘a‘); printf("%lld ", pal.getans()); return 0; }
以上是关于回文树入门的主要内容,如果未能解决你的问题,请参考以下文章