jzoj3291 【JSOI2013】快乐的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|表示字符串A的长度。
JYY希望你帮助他计算出这两个朋友之间关系的紧密程度。

对于100%的数据满足1 ≤|A|,|B| ≤ 50000。

题解

简单的回文树
第一次比赛里打
注意几个细节
1.找不到fail时应该赋值为1
2.匹配时需要同时满足回文树中有点与匹配串中成回文

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 5e4+10;
char a[N],b[N];
int n,m;
int c[N][26],len[N],fail[N],tot,last;
long long ans;
long long cnt[N];
int main() {
    freopen("jyy.in","r",stdin);
    scanf("%s\n%s",a+1,b+1);
    n = strlen(a+1), m = strlen(b+1);
    tot = 1;
    len[0] = -1, fail[1] = 0;
    for (int i=1; i<=n; i++) {
        int r = a[i] - 'A';
        while (a[i] != a[i - len[last] - 1]) 
            last = fail[last];

        if (c[last][r] == 0) {
            bool is = (last == 0);

            c[last][r]=++tot;
            len[c[last][r]] = len[last] + 2;
            int k = fail[last];

            last = c[last][r];
            if (!is) {
                while (a[i] != a[i - len[k] - 1]) 
                    k = fail[k];

                fail[last] = c[k][r];
            } else fail[last] = 1;

        } else last = c[last][r];
        cnt[last] ++;
    }

    for (int i=tot; i; i--) cnt[fail[i]]+=cnt[i];
    cnt[0] = cnt[1] = 0;
    for (int i=1; i<=tot; i++) {
        cnt[i]+=cnt[fail[i]];
    }

    int now = 0;
    for (int i=1; i<=m; i++) {
        int r = b[i] - 'A';
        while (now && (c[now][r] == 0 || i - len[now] - 1 <= 0 || b[i] != b[i - len[now] -1])) now = fail[now];
        now = c[now][r];
        ans += cnt[now];
    }

    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/jokerwyt/article/details/81005770