[JSOI2013]快乐的 JYY

一、题目

点此看题

二、解法

回文自动机板题,我们先建出两个回文自动机,把每一次的 L a s t Last 打上标记,然后再对 f a i l fail 树内的标记求和,算出来就是这个点的回文串出现次数。然后我们在两个自动机一起跑,只需要保证经过的转移相同那么就有最后得到的回文串相同,我们把经过的两棵树的出现次数相乘在累加就是答案,注意 0 , 1 0,1 都要跑一遍。

时间复杂度 O ( n ) O(n) ,那就贴个代码吧。

#include <cstdio>
#include <cstring>
const int M = 50005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int n;char s[M];long long ans;
struct node
{
    int fail,len,ch[26];
    node() {memset(ch,0,sizeof ch);fail=len=0;}
};
struct Pam
{
    node b[M];int n,last,cnt,f[M];
    Pam()
    {
        b[0].fail=1;b[1].len=-1;
        cnt=1;
    }
    int get_fail(int x)
    {
        while(s[n-b[x].len-1]^s[n])
            x=b[x].fail;
        return x;
    }
    void ins()
    {
        n++;
        int p=get_fail(last),c=s[n]-'A';
        if(!b[p].ch[c])
        {
            b[++cnt].len=b[p].len+2;
            int tmp=get_fail(b[p].fail);
            b[cnt].fail=b[tmp].ch[c];
            b[p].ch[c]=cnt;
        }
        last=b[p].ch[c];
        f[last]++;
    }
    void sol()
    {
        for(int i=cnt;i;i--) f[b[i].fail]+=f[i];
    }
}A,B;
void dfs(int x,int y)
{
    if(x+y>2) ans+=1ll*A.f[x]*B.f[y];
    for(int i=0;i<26;i++)
        if(A.b[x].ch[i] && B.b[y].ch[i])
            dfs(A.b[x].ch[i],B.b[y].ch[i]);
}
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++) A.ins();
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++) B.ins();
    A.sol();B.sol();
    dfs(1,1);dfs(0,0);
    printf("%lld\n",ans);
}
发布了257 篇原创文章 · 获赞 13 · 访问量 6720

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104196669