gym-100548G-回文树

题意:给你两个字符串,问你这两个字符串中相同的回文子串的乘积和

解题思路:建立两颗树,然后一起遍历这两颗树就行了,因为是回文树的特点,如果当前两棵树都出现了某一回文子串,那么这回文子串的长度-2也一定出现了,按照这个规律,直接dfs遍历

代码:

#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int maxn=500005;
 
int T,n,len[maxn],sum[maxn][2],zt,m,p;
int ch[maxn][27],fl[maxn],cnt,now,c;
char s[maxn];
ll ans;
 
inline void init(){
    ans=zt=0,fill(s,s+n+1,0);
    for(int i=0;i<=cnt;i++) memset(ch[i],0,sizeof(ch[i]));
    for(int i=0;i<=cnt;i++) sum[i][0]=sum[i][1]=0;
    fill(len,len+cnt+1,0);
    fill(fl,fl+cnt+1,0);
}
 
inline void solve(){
    fl[0]=1,len[1]=-1,cnt=now=1;
     
    for(int i=1;i<=n;i++,now=ch[now][c],sum[now][zt]++){
        if(i>m) zt=1; c=s[i]-'a';
         
        for(;s[i-len[now]-1]!=s[i];now=fl[now]);
         
        if(!ch[now][c]){
            ch[now][c]=++cnt;
            len[cnt]=len[now]+2;
             
            if(len[cnt]==1) continue;
             
            p=fl[now];
            for(;s[i-len[p]-1]!=s[i];p=fl[p]);
            fl[cnt]=ch[p][c];
        }
    }
     
    for(int i=cnt;i>=2;i--){
        sum[fl[i]][0]+=sum[i][0];
        sum[fl[i]][1]+=sum[i][1];
        ans+=sum[i][0]*(ll)sum[i][1];
    }
}
 
int main(){
    scanf("%d",&T);
    for(int o=1;o<=T;o++){
        init();
         
        scanf("%s",s+1),s[0]='?',m=strlen(s+1);
        s[m+1]='z'+1,scanf("%s",s+m+2),n=strlen(s+1);
         
        solve(),printf("Case #%d: %I64u\n",o,ans);
    }
     
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/huangdao/p/10805967.html