zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    WebBrowser
    hibernate关系映射(多对多)
    hibernate关系映射(多对一)
    使用maven构建hibernate
    使用maven构建web项目
    Chapter 6 ViewController
    Chapter 5 带颜色的同心圆
    Symbol(s) not found for architecture arm64
    反射实现NSCodingProtocol 帮助类
    UITableView默认选中第一行
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7860822.html
Copyright © 2011-2022 走看看