【Aizu2292】Common Palindromes(回文树)

【Aizu2292】Common Palindromes(回文树)

题面

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

题解

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

#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;
}

posted @ 2018-06-07 20:38  小蒟蒻yyb  阅读(412)  评论(0编辑  收藏  举报