Aizu2292 Common Palindromes

题意

我也不知道哪里来的OJ (vjudge) 上的
给定两个字符串 (S,T) ,询问 ((i,j,k,l)) 这样的四元组个数
使得 (S[i,j],T[k,l]) 是相等的回文串

Sol

回文树
记录 (S) 的每个回文串的出现位置的集合大小
匹配 (T) 记录其每个回文串出现的位置集合大小
相乘即可

# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

IL int Input(){
	RG int x = 0, z = 1; RG char c = getchar();
	for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
	for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
	return x * z;
}

const int maxn(5e4 + 5);

int son[26][maxn], len[maxn], num[maxn], fa[maxn], vis[maxn];
int tot, n, last;
char s[maxn], t[maxn];

IL void Extend(RG int pos, RG int c){
	RG int p = last;
	while(s[pos - len[p] - 1] != s[pos]) p = fa[p];
	if(!son[c][p]){
		RG int np = ++tot, q = fa[p];
		while(s[pos - len[q] - 1] != s[pos]) q = fa[q];
		len[np] = len[p] + 2, fa[np] = son[c][q];
		son[c][p] = np;
	}
	last = son[c][p], ++num[last];
}

int main(){
	scanf(" %s %s", s + 1, t + 1), n = strlen(s + 1);
	fa[0] = fa[1] = tot = 1, len[1] = -1;
	for(RG int i = 1; i <= n; ++i) Extend(i, s[i] - 'A');
	n = strlen(t + 1);
	for(RG int i = 1, nw = 1; i <= n; ++i){
		RG int c = t[i] - 'A';
		while(nw != 1 && (!son[c][nw] || t[i - len[nw] - 1] != t[i])) nw = fa[nw];
		if(son[c][nw] && t[i - len[nw] - 1] == t[i]) nw = son[c][nw];
		++vis[nw];
	}
	for(RG int i = tot; i; --i) num[fa[i]] += num[i], vis[fa[i]] += vis[i];
	RG ll ans = 0;
	for(RG int i = 2; i <= tot; ++i) ans += 1LL * num[i] * vis[i];
	printf("%lld
", ans);
	return 0;
}

原文地址:https://www.cnblogs.com/cjoieryl/p/9153750.html