回文树学习: 大佬博客
题意:字符串的值 小号s等于此字符串中出现的不同字母的数量。您的任务是计算所有回文子串的总值。
题解:我们建立回文树,用bitset存每个回文子串用了哪些字母,然后设dp[i]为以 i 结尾的所有回文子串的所有字母种类数,我们通过fail指针找到 i 的fail节点 j,显然dp[i] = dp[j] + 以 i 结尾的最长回文子串种类数。
来自:橘子猫
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10;
char str[N];
struct Ptree {
int s[N], next[N][26], fail[N], cnt[N], num[N], len[N];
int p, n, last;
int dp[N];
bitset<26> pika[N];
ll ans = 0;
int build(int l){
for(int i = 0; i < 26; i++)
next[p][i] = 0;
cnt[p] = num[p] = 0;
len[p] = l;
return p++;
}
void init(){
p = 0;
build(0);
build(-1);
s[0] = -1;
fail[0] = 1;
n = last = 0;
}
int getfail(int x){
while(s[n-len[x]-1] != s[n]) x = fail[x];
return x;
}
void add(char c){
c -= 'a';
s[++n] = c;
int cur = getfail(last);
if(!next[cur][c]){
int now = build(len[cur] + 2);
pika[now] = pika[cur];
pika[now][c] = 1;
fail[now] = next[ getfail(fail[cur]) ][c];
next[cur][c] = now;
num[now] = num[fail[now]] + 1;
}
last = next[cur][c];
dp[last] = dp[fail[last]] + pika[last].count();
ans += dp[last];
cnt[last] ++;
}
void count(){
for(int i = p - 1; i >= 0; i--)
cnt[fail[i]] += cnt[i];
}
}pt;
int main(){
cin >> str;
pt.init();
int len = strlen(str);
for(int i = 0; i < len; i++){
pt.add(str[i]);
}
cout << pt.ans;
return 0;
}