Luogu P5685 [JSOI2013]快乐的 JYY
我们对两个 PAM
同时开始 dfs
,因为起始状态相同,那么如果遇到相同的转移就说明有相同的状态,把 \(sz_x\times sz_y\) 作为贡献加到答案里面即可。注意要分别从两个根 dfs
。
#include<iostream>
#include<cstdio>
#include<cstring>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=50010;
int n;
ll ans;
char s[N];
struct PAM {
int tot,lst,fa[N],c[N][26],len[N],sz[N];
inline void init() {len[fa[fa[1]=0]=tot=1]=-1;}
inline int jmp(int p,int i)
{while(s[i-len[p]-1]!=s[i]) p=fa[p]; return p;}
inline void add(int ch,int i) {
R p=jmp(lst,i); if(!c[p][ch]) {
R np=++tot; len[np]=len[p]+2;
R t=jmp(fa[p],i);
fa[np]=c[t][ch],c[p][ch]=np;
} ++sz[lst=c[p][ch]];
}
}p1,p2;
inline void dfs(int p,int q) {
ans+=1ll*p1.sz[p]*p2.sz[q];
for(R i=0;i<26;++i)
if(p1.c[p][i]&&p2.c[q][i]) dfs(p1.c[p][i],p2.c[q][i]);
}
inline void main() {
scanf("%s",s+1),n=strlen(s+1),p1.init();
for(R i=1;i<=n;++i) p1.add(s[i]-'A',i);
for(R i=p1.tot;i>=2;--i) p1.sz[p1.fa[i]]+=p1.sz[i];
scanf("%s",s+1),n=strlen(s+1),p2.init();
for(R i=1;i<=n;++i) p2.add(s[i]-'A',i);
for(R i=p2.tot;i>=2;--i) p2.sz[p2.fa[i]]+=p2.sz[i];
p1.sz[0]=p1.sz[1]=p2.sz[0]=p2.sz[1]=0;
dfs(1,1),dfs(0,0);
printf("%lld\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.16