zoukankan      html  css  js  c++  java
  • [TJOI2015] 弦论

    题目描述

    给定一个字符串。

    求这个字符串的字典序第 (k) 大的本质不同子串(不同位置只算一次)。

    求这个字符串的字典序第 (k) 大的子串(不同位置算多次)。

    正解

    建出后缀自动机,把每一个点往后走有多少种方案求出来,就可以 (O(n)) 定位字符串了。

    一个点往后走的方案等于所有后继节点(不仅仅是直接后继,还包括可以走到的节点)所代表的字符串的方案(或者说是出现次数)求和。

    一个节点所代表的字符串的方案分下面两类讨论:

    ( exttt{t = 0}),出现多次算一次

    在后缀自动机上面移动,走到一个字符串的方案唯一。

    也就是说,所有移动的方案本质不同。

    那么一个节点方案就是 (1)

    ( exttt{t = 1}),出现多次算多次

    自动机上一个点的方案设为它的出现次数((endpos) 集合大小)。

    一个点 (endpos) 集合大小就是对其 (parent) 树的子树求个和(先把原字符串结尾位置对应的节点初始化为 (1))。

    代码

    /*
        t = 0, 出现多次算一次
        t = 1, 出现多次算多次
    */
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 5e5 + 5;
    
    int n, k, t;
    int pos[N];
    char s[N];
    
    int last, vcnt;
    int deg[N << 1];
    
    struct node {
        int link, len, siz;
        int to[26];
    } a[N << 1];
    
    void extend(int c) {
        int p = last, cur = ++vcnt;
        a[cur].len = a[last].len + 1;
        while(~p && !a[p].to[c]) {
            a[p].to[c] = cur;
            p = a[p].link;
        }
        if(p == -1) {
            a[cur].link = 0;
        } else {
            int q = a[p].to[c];
            if(a[q].len == a[p].len + 1) {
                a[cur].link = q;
            } else {
                int clone = ++vcnt;
                a[clone] = a[q];
                a[clone].len = a[p].len + 1;
                while(~p && a[p].to[c] == q) {
                    a[p].to[c] = clone;
                    p = a[p].link;
                }
                a[q].link = a[cur].link = clone;
            }
        }
        last = cur;
    }
    
    long long f[N << 1];
    long long getFunc(int u) {
        if(f[u] != -1) return f[u];
        long long &F = f[u]; F = a[u].siz;
        for(int c = 0, v; c < 26; ++c) {
            v = a[u].to[c];
            if(v == 0) continue;
            F += getFunc(v);
        }
        return F;
    }
    void dfs(int u, int rem) {
        rem -= a[u].siz;
        if(rem <= 0) return void();
        for(int c = 0, v; c < 26; ++c) {
            v = a[u].to[c];
            if(v == 0) continue;
            if(rem > f[v]) {
                rem -= f[v];
            } else {
                putchar('a' + c);
                dfs(v, rem);
                break;
            }
        }
    }
    
    int main() {
        scanf("%s %d %d", s + 1, &t, &k);
        n = strlen(s + 1);
        a[last = 0].link = -1;
        for(int i = 1; i <= n; ++i) {
            extend(s[i] - 'a');
            pos[i] = last;
        }
        if(!t) {
            for(int i = 1; i <= vcnt; ++i)
                a[i].siz = 1;
        } else {
            for(int i = 1; i <= n; ++i)
                ++a[pos[i]].siz;
            for(int i = 1; i <= vcnt; ++i)
                ++deg[a[i].link];
            queue<int> Q;
            for(int i = 1; i <= vcnt; ++i)
                if(deg[i] == 0)
                    Q.push(i);
            while(!Q.empty()) {
                int u = Q.front(), v = a[u].link; Q.pop();
                if(v == 0) continue;
                a[v].siz += a[u].siz;
                if(--deg[v] == 0) Q.push(v);
            }
        }
    
        memset(f, -1, sizeof f);
        getFunc(0);
        
        if(f[0] < k) {
            puts("-1");
        } else {
            dfs(0, k);
            putchar('
    ');
        }
        return 0;
    }
    
  • 相关阅读:
    java连接Oracle数据库实现增删改查并在Navicat中显示
    《程序员修炼之道:从小工到专家》 阅读笔记06
    VirtualBox 共享文件夹设置及使用方法
    Access denied for user 'root'@'localhost' (using password:YES)
    错误记录
    java.lang.NoClassDefFoundError: org/apache/hadoop/hbase/HBaseConfiguration] with root cause
    VirtualBox查看虚拟机IP地址
    用户不在sudoers文件中,此事将被报告
    简单窗口与hbase数据库相连
    AS安装过程中出现的错误
  • 原文地址:https://www.cnblogs.com/Lskkkno1/p/12886184.html
Copyright © 2011-2022 走看看