zoukankan      html  css  js  c++  java
  • [LuoguP2408]不同子串个数(后缀自动机)

    题目传送门

    先建好后缀自动机,然后答案就是$sum_{u in 状态集合}len[u]-len[link[u]]$。

    为什么这样是对的?

    每个状态所代表的字符串是没有交集的,所以我们只需求出每个状态有多少个子串。

    其实在学习构建SAM的时候我们学过link的一个性质,就是len[link[x]]+1=min_len(x),且一个状态内的字符串按长度从小到大排序是连续的。

    通过这个性质很容易得到上面的式子。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1000010;
    struct SAM{
        int ch[26], link, len;
    }tr[N];
    int lst = 1, tot = 1;
    int n;
    long long ans;
    char s[N];
    void insert(int c) {
        int p = lst;
        int np = lst = ++tot;
        tr[np].len = tr[p].len + 1;
        while (p && !tr[p].ch[c]) tr[p].ch[c] = np, p = tr[p].link;
        if (!p) tr[np].link = 1;
        else {
            int q = tr[p].ch[c];
            if (tr[q].len == tr[p].len + 1) tr[np].link = q;
            else {
                int nq = ++tot;
                tr[nq] = tr[q];
                tr[nq].len = tr[p].len + 1;
                tr[q].link = tr[np].link = nq;
                while (p && tr[p].ch[c] == q) tr[p].ch[c] = nq, p = tr[p].link;
            }
        }
    }
    int main() {
        cin >> n;
        scanf("%s", s + 1);
        for (int i = 1; i <= n; i++) {
            insert(s[i] - 'a');
        }
        for (int i = 2; i <= tot; i++) {
            ans += tr[i].len - tr[tr[i].link].len;
        }
        cout << ans;
        return 0;
    }
  • 相关阅读:
    继承与 接口
    数组
    字符串加密
    类与对象
    java 方法学习
    课堂练习
    第一次课堂任务记录。整形数字相加合输出
    《大道至简》第二章 读后感
    大道至简第二章
    大道至简第一章
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13121907.html
Copyright © 2011-2022 走看看