• 落谷P1872 回文串计数(回文树)


    传送门

    这道题显然可以用PAM做出来。

    PAM可以算出以字符串的第ii个字符为结尾的回文子串的个数。我们将其存到一个数组l[n],再求一个前缀和就可以把字符串的前i个字符的前缀有多少个回文子串求出来。

    然后,我们将PAM清空,倒着做一遍,就可以求出以第i个字符为左端点的回文子串个数r[i]。与它不相交的回文子串且在它前面的子串有l[i - 1]个,相乘再累加就是答案。

    此题在落谷的评级是绿,那是因为此题数据范围只有2000,不用PAM也可以做。但此题可以当做PAM入门的练手题。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    using namespace std;
    const int N = 200000;
    struct Plalindromic_Tree{
        int go[26], len, fail;
        ll fail_len;
    }pt[N];
    int lst, tot;
    char s[N], ss[N];
    void build() {
        lst = tot = 0;
        ss[0] = -1;
        pt[++tot].len = -1;
        pt[0].fail = pt[1].fail = 1;
        pt[0].fail_len = 2;
        pt[1].fail_len = 1;
    }
    int add(int c, int n) {
        int p = lst;
        ss[n] = c + 'a';
        while (ss[n - pt[p].len - 1] != ss[n]) p = pt[p].fail;
        if (!pt[p].go[c]) {
            int v = ++tot, k = pt[p].fail;
            pt[v].len = pt[p].len + 2;
            while (ss[n - pt[k].len - 1] != ss[n]) k = pt[k].fail;
            pt[v].fail = pt[k].go[c];
            pt[v].fail_len = pt[pt[v].fail].fail_len + 1;
            pt[p].go[c] = v;
        }
        return lst = pt[p].go[c];
    }
    ll r[N], ans;
    int lens;
    int main() {
        scanf("%s", s + 1);
        lens = strlen(s + 1);
        build();
        for (int i = 1; i <= lens; i++) {
            r[i] = (pt[add(s[i] - 'a', i)].fail_len - 2) + r[i - 1];
        }
    //    cout<< endl;
        memset(pt, 0, sizeof(pt));
        build();
        for (int i = lens; i > 1; i--) {
            ans += (pt[add(s[i] - 'a', lens - i + 1)].fail_len - 2) * r[i - 1];
        }
        cout << ans;
        return 0;
    }
  • 相关阅读:
    shell 冒泡算法 解决数组排序问题
    react(二)
    react(一)
    mybatis-plus:3
    lambda
    配置中心(nacos)-控制台使用
    nacos作为配置中心的简单项目配置
    nacos作为注册中心的简单项目配置
    Vue初步学习
    nacos单例模式简单搭建
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12394727.html
Copyright © 2020-2023  润新知