洛谷_5685 [JSOI2013]快乐的 JYY(回文自动机)

[JSOI2013]快乐的 JYY

题目链接:https://www.luogu.com.cn/problem/P5685

题解:

回文自动机。对两个字符串分别构造回文自动机。统计每个回文子串出现的次数。
DFS。对两个自动机DFS,对于两个自动机共有的回文子串,ans+=两个自动机该串出现次数的乘积。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
 
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 50010;
const int mod = 1000000007;
struct Pam{
    char s[maxn];
    int cnt, slen, last;
    int len[maxn], tim[maxn], num[maxn], fail[maxn], nex[maxn][26];
    void init()
    {
        cnt = -1;
        slen = last = 0;
        s[0] = '*';
        creat(0);
        creat(-1);
        fail[0] = 1;
    } 

    int creat(int x)
    {
        cnt++;
        len[cnt] = x;
        memset(nex[cnt], 0, sizeof(nex[cnt]));
        num[cnt] = tim[cnt] = 0;
        return cnt;
    }

    int getfail(int x)
    {
        while(s[slen-len[x]-1] != s[slen])x = fail[x];
        return x;
    }

    void Insert(char ch)
    {
        s[++slen] = ch;
        int x = ch-'A', cur = getfail(last);
        if(!nex[cur][x]){
            int now = creat(len[cur]+2);
            fail[now] = nex[getfail(fail[cur])][x];
            nex[cur][x] = now;
        }
        last = nex[cur][x];
        tim[last]++;
    }

    void getsum()
    {
        for(int i=cnt;i>1;i--)
            tim[fail[i]] += tim[i];
    }
}st1, st2;
int mx, num;
LL ans;
char str1[maxn], str2[maxn];
void dfs(int id1, int id2);

int main()
{
    int n, m, i, j, k;
    scanf("%s %s", str1, str2);
    st1.init();
    for(i=0;str1[i];i++)
        st1.Insert(str1[i]);
    st1.getsum();
    st2.init();
    for(i=0;str2[i];i++)
        st2.Insert(str2[i]);
    st2.getsum();
    dfs(0, 0);
    dfs(1, 1);
    printf("%lld\n", ans);
    return 0;
}

void dfs(int id1, int id2)
{
    if(id1!=0 && id1 != 1)ans += 1LL*st1.tim[id1]*st2.tim[id2];
    for(int i=0;i<26;i++)
        if(st1.nex[id1][i] && st2.nex[id2][i])
            dfs(st1.nex[id1][i], st2.nex[id2][i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值