• bzoj3473


    广义后缀自动机

    具体我也不是很清楚

    像这样有很多个串要统计方案的题我们建一个广义后缀自动机,就是每次对一个串建完后把last设为root,然后就是每个串在自动机上跑一遍,记录每个节点的访问次数,为了避免重复,我们记录当前这个节点这个字符串走没走过,出现次数也是要向上推的。最后按照套路把贡献向上推,再走一遍加上每个点的贡献就是答案。

     
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 5;
    int n, k;
    int a[N], c[N];
    string s[N];
    char tc[N];
    ll f[N];
    namespace SAM
    {
        struct node {
            int val, par, cnt, last;
            int ch[26];
        } t[N];
        int last = 1, root = 1, sz = 1;
        int nw(int x)
        {
            t[++sz].val = x;
            return sz;
        }
        void extend(int c)
        {
            int p = last, np = nw(t[p].val + 1);
            while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
            if(!p) t[np].par = root;
            else
            {
                int q = t[p].ch[c];
                if(t[q].val == t[p].val + 1) t[np].par = q;
                else
                {
                    int nq = nw(t[p].val + 1);
                    memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch));
                    t[nq].par = t[q].par;
                    t[q].par = t[np].par = nq;
                    while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
                }
            }
            last = np;
        }
    } using namespace SAM;
    int main()
    {
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%s", tc);
            s[i] = string(tc);
            int len = strlen(tc);
            last = root;
            for(int j = 0; j < len; ++j) extend(tc[j] - 'a');
        }
        for(int i = 1; i <= n; ++i)
        {
            int u = root, ans = 0;
            for(int j = 0; j < s[i].size(); ++j) 
            {
                u = t[u].ch[s[i][j] - 'a'];
                int p = u;
                while(p) 
                {
                    if(t[p].last != i) 
                    {
                        ++t[p].cnt;
                        t[p].last = i;
                    }
                    else break;
                    p = t[p].par;
                }
            }
        }
        for(int i = 1; i <= sz; ++i) ++c[t[i].val];
        for(int i = 1; i <= sz; ++i) c[i] += c[i - 1];
        for(int i = 1; i <= sz; ++i) a[c[t[i].val]--] = i;
        t[1].cnt = 0;
        for(int i = 1; i <= sz; ++i)
        {
            int u = a[i];
            f[u] += f[t[u].par] + (t[u].cnt >= k ? t[u].val - t[t[u].par].val : 0);
        }
        for(int i = 1; i <= n; ++i)
        {
            int u = root;
            ll ans = 0;
            for(int j = 0; j < s[i].size(); ++j)
            {
                u = t[u].ch[s[i][j] - 'a'];
                ans += f[u];
            }
            printf("%lld ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    js 或者 element-ui 将年月日时分秒转换为时间戳
    element-ui 设置table 表头多列显示
    element-ui table 给表头添加icon,以及hover上去的提示文字
    js 获取本周开始结束时间,本月开始结束时间等....
    element-ui Table 翻页后记忆之前勾选
    element-ui 上传图片或视频时,先回显在上传
    element-ui Upload 上传获取当前选择的视频时长
    element-ui 自定义 Upload 上传进度条
    Sqoop(二)常用命令及常数解析
    使用IDEA构建Spring Boot项目简单实例
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7860822.html
Copyright © 2020-2023  润新知