【Aizu2292】Common Palindromes(回文树)

题面

Vjudge
神TMD日语
翻译:
给定两个字符串 S , T ,询问 ( i , j , k , l ) 这样的四元组个数
满足 S [ i , j ] , T [ k , l ] 都是回文串并且 S [ i , j ] = T [ k , l ]

题解

自己 y y 一下就会做了
回文树又叫做回文自动机,所以当然可以用来进行回文串的识别和匹配了
对于一个串构建 P A M 或者说回文树,统计一下每个回文串的出现次数
再用另外一个串在 P A M 上进行匹配,计算一下每个节点被访问的次数
最后把每个节点的两个值乘起来求和就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 55555
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct PAM
{
    struct Node{int son[26],len,ff,v;}t[MAX];
    int tot,last;
    void init(){t[tot=1].len=-1;t[0].ff=t[1].ff=1;}
    void extend(int c,int n,char *s)
    {
        int p=last;
        while(s[n-t[p].len-1]!=s[n])p=t[p].ff;
        if(!t[p].son[c])
        {
            int v=++tot,k=t[p].ff;
            while(s[n-t[k].len-1]!=s[n])k=t[k].ff;
            t[v].len=t[p].len+2;
            t[v].ff=t[k].son[c];
            t[p].son[c]=v;
        }
        last=t[p].son[c];
        t[last].v++;
    }
}P;
int f[MAX];
char ch[MAX];
ll ans=0;
int main()
{
    P.init();
    scanf("%s",ch+1);
    for(int i=1,l=strlen(ch+1);i<=l;++i)P.extend(ch[i]-65,i,ch);
    scanf("%s",ch+1);
    for(int i=1,l=strlen(ch+1),now=1;i<=l;++i)
    {
        int c=ch[i]-65;
        while(now!=1&&(!P.t[now].son[c]||ch[i]!=ch[i-P.t[now].len-1]))now=P.t[now].ff;
        if(P.t[now].son[c]&&ch[i]==ch[i-P.t[now].len-1]){now=P.t[now].son[c];f[now]++;}
        else now=1;
    }
    for(int i=P.tot;i;--i)f[P.t[i].ff]+=f[i];
    for(int i=P.tot;i;--i)P.t[P.t[i].ff].v+=P.t[i].v;
    for(int i=1;i<=P.tot;++i)
        ans+=1ll*f[i]*P.t[i].v;
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30974369/article/details/80614582