P3975 [TJOI2015]弦论

传送门

题目大意

对于一个给定的长度为 \(n(1\le n\le5\cdot10^5)\) 的字符串,求出它的第 \(k(1\le k\le10^9)\) 小子串,输入 \(t\)\(t=0\) 时不同位置的相同子串算作一个, \(t=1\) 时算作多个,如果子串数量 \(<k\) ,输出 \(-1\)

思路

\(sam\) 中本质不同的子串个数为从初始节点出发的总路径数,可以对每个节点求出从其出发的总路径数 \(f_v\) ,代表该到达该节点后还能获得的不同子串数,对 \(sam\) 进行拓扑排序,有 \(f_v=1+\sum_{(u,v)\in sam}f_u\) 。如果不同位置的子串算作多个,将 \(1\) 改为 \(|right_v|\) 即可,注意不要算入空串。之后从初始节点开始贪心即可求得答案。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<int, int>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mk make_pair
//#define int LL
#define lc P*2
#define rc P*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const LL MOD = 1000000009;
const LL mod = 998244353;
const int maxn = 500010;

string S;
LL T, K;
int tot = 1, last = 1;

struct Node {
    int len, fa;
    int ch[26];
    bool isnp;
}sam[maxn * 3];
vector<int>G[maxn * 3], SAM[maxn * 3];
LL siz[maxn * 3], f[maxn * 3], g[maxn * 3], in[maxn * 3];
queue<int>que;

void add_edge(int from, int to)
{
    G[from].push_back(to);
}

void add_edge2(int from, int to)
{
    SAM[from].push_back(to);
}

void extend(char c)
{
    int p = last, np = last = ++tot;
    sam[np].len = sam[p].len + 1;
    sam[np].isnp = true;
    for (; p && !sam[p].ch[c]; p = sam[p].fa)
        sam[p].ch[c] = np;
    if (!p)
        sam[np].fa = 1;
    else
    {
        int q = sam[p].ch[c];
        if (sam[q].len == sam[p].len + 1)
            sam[np].fa = q;
        else
        {
            int nq = ++tot;
            sam[nq] = sam[q], sam[nq].len = sam[p].len + 1;
            sam[nq].isnp = false;
            sam[q].fa = sam[np].fa = nq;
            for (; p && sam[p].ch[c] == q; p = sam[p].fa)
                sam[p].ch[c] = nq;
        }
    }
}

void dfs1(int v)
{
    siz[v] = sam[v].isnp;
    for (auto& to : G[v])
    {
        dfs1(to);
        siz[v] += siz[to];
    }
}

void solve()
{
    for (int i = 0; i < S.size(); i++)
        extend(S[i] - 'a');
    for (int i = 2; i <= tot; i++)
        add_edge(sam[i].fa, i);
    for (int i = 1; i <= tot; i++)
    {
        for (int j = 0; j < 26; j++)
        {
            if (sam[i].ch[j])
                add_edge2(sam[i].ch[j], i), in[i]++;
        }
    }
    for (int i = 1; i <= tot; i++)
    {
        if (in[i] == 0)
            que.push(i);
    }
    dfs1(1);
    while (!que.empty())
    {
        int v = que.front();
        que.pop();
        if (v != 1)
            f[v]++, g[v] += siz[v];
        for (auto& to : SAM[v])
        {
            f[to] += f[v], g[to] += g[v];
            in[to]--;
            if (in[to] == 0)
                que.push(to);
        }
    }
    int now = 1;
    string ans = "";
    if (T == 0)
    {
        if (f[1] < K)
        {
            cout << -1 << endl;
            return;
        }
        while (true)
        {
            if (now > 1)
            {
                if (K == 1)
                    break;
                K--;
            }
            for (int i = 0; i < 26; i++)
            {
                if (!sam[now].ch[i])
                    continue;
                if (f[sam[now].ch[i]] < K)
                    K -= f[sam[now].ch[i]];
                else
                {
                    ans += i + 'a';
                    now = sam[now].ch[i];
                    break;
                }
            }
        }
    }
    else
    {
        if (g[1] < K)
        {
            cout << -1 << endl;
            return;
        }
        while (true)
        {
            if (now > 1)
            {
                if (K <= siz[now])
                    break;
                K -= siz[now];
            }
            for (int i = 0; i < 26; i++)
            {
                if (!sam[now].ch[i])
                    continue;
                if (g[sam[now].ch[i]] < K)
                    K -= g[sam[now].ch[i]];
                else
                {
                    ans += i + 'a';
                    now = sam[now].ch[i];
                    break;
                }
            }
        }
    }
    cout << ans << endl;
}

int main()
{
    IOS;
    cin >> S >> T >> K;
    solve();

    return 0;
}
posted @ 2022-06-29 14:17  Prgl  阅读(39)  评论(0)    收藏  举报