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

posted @ 2020-01-16 19:27  LuitaryiJack  阅读(115)  评论(0编辑  收藏  举报