「Codechef April Lunchtime 2015」Palindromeness
解题思路 :
考虑对于回文子串 (s) 贡献的定义:
[value_s = [ s[1,lfloor frac{|s|}{2}
floor] ext{ is palindrome}] imes value_{s[1,lfloor frac{|s|}{2}
floor]} + 1
]
也就是说对于每一个回文子串,只需要判断其前一半的字符是不是回文串并得到贡献即可。
于是建出回文树,可以通过跳 (fail) 得到其所有回文前缀,用倍增找到第一个长度小于等于一半的回文前缀,判断其长度是否恰好是一半并继承贡献。
令 (size_u) 表示回文树上一个节点所代表的回文串的 (right) 集合大小,则
[Ans =sum_{u ext{ in pam}} size_u imes value_u
]
总复杂度 (O(|s|log|s|)) 。
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf ((int)(1e9))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 200005;
char s[N];
namespace PAM{
ll ans;
int ch[N][26], sz[N], fa[N], len[N], f[N][21], val[N], size, tail;
inline int newnode(int x){ return len[++size] = x, size; }
inline void init(){
memset(ch, 0, sizeof(ch));
memset(fa, 0, sizeof(fa));
memset(sz, 0, sizeof(sz));
len[1] = -1, fa[0] = 1, size = tail = 1, ans = 0;
}
inline void pushback(int pos){
int c = s[pos] - 'a', p = tail;
while(s[pos-len[p]-1] != s[pos]) p = fa[p];
if(ch[p][c]) return (void) (sz[tail=ch[p][c]]++);
int np = newnode(len[p] + 2), u = fa[p];
while(s[pos-len[u]-1] != s[pos]) u = fa[u];
fa[np] = ch[u][c], sz[tail=ch[p][c]=np]++;
}
inline void solve(){
for(int i = 1; i <= size; i++) f[i][0] = fa[i];
for(int j = 1; j <= 20; j++)
for(int i = 1; i <= size; i++)
f[i][j] = f[f[i][j-1]][j-1];
for(int i = 2; i <= size; i++){
val[i] = 1; int x = i;
for(int j = 20; ~j; j--)
if(len[f[x][j]] >= len[i] / 2) x = f[x][j];
if(len[x] == len[i] / 2) val[i] += val[x];
}
for(int i = size; i > 2; i--) sz[fa[i]] += sz[i];
for(int i = 2; i <= size; i++) ans += 1ll * val[i] * sz[i];
cout << ans << endl;
}
}
int main(){
int T; read(T);
while(T--){
scanf("%s", s + 1); int n = strlen(s + 1);
PAM::init();
for(int i = 1; i <= n; i++) PAM::pushback(i);
PAM::solve();
}
return 0;
}