「Codechef April Lunchtime 2015」Palindromeness

「Codechef April Lunchtime 2015」Palindromeness

解题思路 :

考虑对于回文子串 \(s\) 贡献的定义:

\[value_s = [\ s[1,\lfloor \frac{|s|}{2}\rfloor]\text{ is palindrome}]\times value_{s[1,\lfloor \frac{|s|}{2}\rfloor]} + 1 \]

也就是说对于每一个回文子串,只需要判断其前一半的字符是不是回文串并得到贡献即可。

于是建出回文树,可以通过跳 \(fail\) 得到其所有回文前缀,用倍增找到第一个长度小于等于一半的回文前缀,判断其长度是否恰好是一半并继承贡献。

\(size_u\) 表示回文树上一个节点所代表的回文串的 \(right\) 集合大小,则

\[Ans =\sum_{u \text{ in pam}} size_u \times 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;
}
posted @ 2018-12-23 19:43  Joyemang33  阅读(162)  评论(0编辑  收藏  举报