bzoj4480: [Jsoi2013]快乐的jyy 回文自动机

bzoj4480: [Jsoi2013]快乐的jyy

Description

【故事背景】
JYY在JSOI有很多很多的好朋友,比如PUPPY,KFC还有PUPPUP。因为
有了这么多的好朋友,所以JYY每天都很快乐。某天,JYY发现好朋友之间关
系的好坏和名字有很大的关系,比如PUPPY和PUPPUP的关系就特别好,但是
和KFC的关系就很一般。JYY苦思冥想终于发现了其中的规律,现在JYY想知
道两个朋友之间关系的好坏,你能帮助JYY么?
【问题描述】
给定两个字符串A和B,表示JYY的两个朋友的名字。我们用A(i,j)表示A
字符串中从第i个字母到第j个字母所组成的子串。同样的,我们也可以定义B(x,y)。
JYY发现两个朋友关系的紧密程度,等于同时满足如下条件的四元组(i,j,x,y)
的个数:
1:1<=i<=j<=|A|
2:1<=x<=y<=|B|
3:A(i,j)=B(x,y)
4:A(i,j)是回文串
这里表示字符串A的长度。
JYY希望你帮助他计算出这两个朋友之间关系的紧密程度。

Input

数据包行两行由大写字母组成的字符串A和B
1≤|A|,|B|≤50000。

Output

包含一行一个整数,表示紧密程度,也就是满足要求的4元组个数

Sample Input

PUPPY
PUPPUP

Sample Output

17

分析

基本上是裸的。
建两个自动机,相同节点的cnt乘法原理一下即可。

代码

#include<cstdio>
#include<cstring>
const int N = 5e4 + 10;
long long ans;
struct PAM {
    int ch[N][26], len[N], S[N], f[N], cnt[N], sz, ls, L;
    PAM() {len[1] = -1; f[0] = 1; S[0] = -1; sz = 1;}
    int F(int p) {for(;S[L - len[p] - 1] != S[L]; p = f[p]) ; return p;}
    void Extend(int c) {
        S[++L] = c; int p = F(ls), np;
        if(!ch[p][c]) {
            len[np = ++sz] = len[p] + 2;
            f[np] = ch[F(f[p])][c]; ch[p][c] = np;
        }
        ++cnt[ls = ch[p][c]];
    }
    void Cnt() {for(int i = sz; i; --i) cnt[f[i]] += cnt[i];}
    void Work() {
        char ch = getchar(); 
        for(;ch < 'A' || ch > 'Z'; ch = getchar()) ;
        for(;ch >= 'A' && ch <= 'Z'; ch = getchar()) Extend(ch - 'A');
        Cnt();
    }
}p[2];
void Dfs(int u, int v) {
    if(p[0].len[u] > 0) ans += 1LL * p[0].cnt[u] * p[1].cnt[v]; 
    for(int c = 0;c < 26; ++c)
        if(p[0].ch[u][c] && p[1].ch[v][c])
            Dfs(p[0].ch[u][c], p[1].ch[v][c]);
}
int main() {
    p[0].Work(); p[1].Work();
    Dfs(0, 0); Dfs(1, 1); printf("%lld\n", ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值