zoukankan      html  css  js  c++  java
  • bzoj3998

    后缀自动机+dp

    想了挺长时间

    后缀自动机的状态图是一个dag,从root走到一个点的路径数代表了这个状态包含的子串,我们先预处理出来每个节点向后走能够形成多少子串,注意这里不是直接在parent树上求和,我们先求出每个节点的right集合的大小,然后在状态图上统计儿子的路径数,因为向儿子走相当于添加一个字符,所以这里和Max没有关系,那么图上后继的Right和就是之后能够形成多少子串,然后就是查找第k大的过程了。这道题T=0的时候每个点的值都是1,因为相同的算一个,T=1就是Right集合的大小。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e6 + 5;
    int n, k, T; 
    int a[N], c[N], sum[N], val[N];
    char s[N];
    namespace SAM
    {
        struct node {
            int val, par;
            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);
            val[np] = 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;
        }
        void RadixSort()
        {
            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;
            for(int i = sz; i; --i) 
            {
                int u = a[i];
                if(T == 0) val[u] = 1;
                else val[t[u].par] += val[u];
            }
            val[1] = 0;
            for(int i = sz; i; --i) 
            {
                int u = a[i];
                sum[u] = val[u];
                for(int j = 0; j < 26; ++j) if(t[u].ch[j])
                    sum[u] += sum[t[u].ch[j]];
            }
        }
        void print(int u) 
        {
            if(k <= val[u]) return;
            k -= val[u];
            for(int i = 0; i < 26; ++i) if(t[u].ch[i])
            {
                if(k <= sum[t[u].ch[i]]) 
                {
                    printf("%c", 'a' + i);
                    print(t[u].ch[i]);
                    return;
                }
                else k -= sum[t[u].ch[i]];
            }
        }
    } using namespace SAM;
    int main()
    {
        scanf("%s%d%d", s + 1, &T, &k);
        n = strlen(s + 1);
        for(int i = 1; i <= n; ++i) extend(s[i] - 'a');
        RadixSort();
        if(sum[1] < k) 
        {
            puts("-1");
            return 0;
        }   
        print(root);
        return 0;
    }
    View Code
  • 相关阅读:
    开发JQuery插件标准结构
    JavaScript中的正则表达式
    IntelliJ IDEA 之Web的Facets/Artifacts(八)
    IntelliJ IDEA 快捷键(七)
    IntelliJ IDEA 集成各种插件(六)
    [转]VS2010几款超赞的扩展辅助工具总结
    创建和使用动态链接库(转)vs2008 vs2010
    springboot 自定义Repository
    springboot redis 缓存对象
    springboot 集成spring-session redis 实现分布式session
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7857452.html
Copyright © 2011-2022 走看看