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\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjoieryl/p/9153750.html