JZOJ 3291. 【JSOI2013】快乐的JYY

题目大意

给两个字符串。求满足要求的四元组(i,j,x,y)个数。
要求①,A[i..j]=B[x..y]。要求②,A[i..j]是回文串。
其中 |A|,|B|50000 | A | , | B | ≤ 50000

解题思路

一开始想的部分分用SAM处理B。然后 O(|A|2) O ( | A | 2 ) 暴力得出结果。不知道哪里打挂了。
对于A=B的部分分,我想都没想直接上马拉车。后来才发现答案也和SAM的点的right集有关。
结果可想而知。
正解?
回文自动机。
计算一下每个回文串在A,B里分别出现了几次。然后乘起来就好。

在这里口胡一下回文自动机咋搞。
首先,对于字符串S的回文自动机中的每个点存的是本质不同的回文串。
注:对于串ABABA,其中ABA(1..3)和ABA(3..5)是本质相同的回文串。
回文自动机里有2种边:
①trans(x,c)。对于一个回文串x,通过trans(x,c)转移到cxc。即x的左右各添个字符c。
②fail[x]。fail[x]连向x的最长回文后缀。
考虑增量法构建回文自动机。
对于一个字符串S,要增加一个字符串c,如果直接加不能够使得S’=(S+c)成为回文串,那么跳fail边,直到跳到某个点对应的串A,这个A是目前S的一个后缀(这很显然),加上字符c之后又能够产生一个新的回文串B。
则len[B]=len[A]+2.
//跳的时候要从F(fail[np])开始跳……
其实原理和AC自动机差不多。
时间复杂度O(n).
原因:每增加一个字符,最多只会多出1个本质不同的回文子串

代码(裸的回文串)

struct PAM{
    int pam[N][26],len[N],st[N],fail[N],cnt[N],gs,L,wz;
    PAM(){len[1]=-1;fail[0]=1;st[0]=-1;gs=1;}
    int F(int x){for(;st[L-len[x]-1]!=st[L];x=fail[x]);return x;}
    void Extend(int c){
        st[++L]=c;
        int np=F(wz),nq;
        if(!pam[np][c]){
            len[nq=++gs]=len[np]+2;
            fail[nq]=pam[F(fail[np])][c];
            pam[np][c]=nq;
        }
    }
    void Work(){
        char ch=getchar();
        while(ch<'A'||ch>'Z')ch=getchar();
        while(ch>='A'&&ch<='Z')Extend(ch-'A'),ch=getchar();
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值