【BZOJ4310】Flea (suffix array)

Description

Divide a string into no more than k In these substrings, select a substring with the largest lexicographical order (that is, the substring of the substring), which is called "magic string", and find a way to make the lexicographical order of the "magic string" smallest.


Solution

Very good suffix array question!

The largest and the smallest are obviously two points.
Considering the lexicographic ranking of the bisection magic string, we first find the position of the atomic string through the ranking. As for how to judge whether a substring is legal, we can check from the back to the front. If the lexicographical order after adding the current suffix is ​​greater than the substring obtained by bisection , then cut at the back of the current position, and count the number of cuts.


Source

/************************************************
 * Au: Hany01
 * Date: Apr 11th, 2018
 * Prob: [BZOJ4310] 跳蚤
 * Email: [email protected]
************************************************/

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia

template <typename T> inline bool checkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool checkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

inline int read()
{
    register int _, __; register char c_;
    for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}

const int maxn = 100005;

int n, m, tp[maxn << 1], rk[maxn << 1], sa[maxn], c[maxn], f[maxn][18], Log[maxn];
char s[maxn];

inline void RadixSort()
{
    For(i, 0, m) c[i] = 0;
    For(i, 1, n) ++ c[rk[i]];
    For(i, 1, m) c[i] += c[i - 1];
    Fordown(i, n, 1) sa[c[rk[tp[i]]] --] = tp[i];
}

inline void getSA()
{
    For(i, 1, n) rk[i] = s[i], tp[i] = i;
    m = 255, RadixSort();
    for (int k = 1, p; k <= n; k <<= 1)
    {
        p = 0;
        For(i, n - k + 1, n) tp[++ p] = i;
        For(i, 1, n) if (sa[i] > k) tp[++ p] = sa[i] - k;
        RadixSort(), swap(rk, tp), rk[sa[1]] = 1, m = 1;
        For(i, 2, n) rk[sa[i]] = tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + k] == tp[sa[i - 1] + k] ? m : ++ m;
        if (m >= n) return;
    }
}

inline void getHeight()
{
    for (int i = 1, j, k = 0; i <= n; f[rk[i ++]][0] = k)
        for (k = k ? k - 1 : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k] && i + k <= n && j + k <= n; ++ k) ;
    For(i, 2, n) Log[i] = Log[i >> 1] + 1;
    for (register int j = 1; j <= Log[n]; ++ j)
        For(i, 1, n - (1 << j) + 1) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}

inline LL getSum()
{
    LL Ans = 0;
    For(i, 1, n) Ans += n - sa[i] - f[i][0] + 1;
    return Ans;
}

inline PII kth(LL k)
{
    For(i, 1, n)
        if (k > n - f[i][0] - sa[i] + 1) k -= n - f[i][0] - sa[i] + 1;
        else return mp(sa[i], sa[i] + f[i][0] + k - 1);
}

inline int LCP(int x, int y)
{
    x = rk[x], y = rk[y];
    if (x > y) swap(x, y);
    if (x == y) return n - sa[y] + 1;
    ++ x;
    register int t = Log[y - x + 1];
    return min(f[x][t], f[y - (1 << t) + 1][t]);
}

inline bool compare(PII a, PII b)
{
    //Return true if b > a
    if (LCP(a.x, b.x) < min(a.y - a.x + 1, b.y - b.x + 1)) return rk[b.x] > rk[a.x];
    else return b.y - b.x + 1 > a.y - a.x + 1;
}

inline int check(PII pos)
{
    int cnt = 0, j;
    for (int i = n; i >= 1; i = j)
    {
        for (j = i; j >= 1; -- j) if (compare(pos, mp(j, i))) break;
        if (i == j) return INF;
        ++ cnt;
    }
    return cnt;
}

int main()
{
#ifdef hany01
    File("bzoj4310");
#endif

    static int k;
    static LL L, R, M;

    k = read(), scanf("%s", s + 1), n = strlen(s + 1);
    getSA(), getHeight();

    L = 1, R = getSum();
    while (L < R)
        if (check(kth(M = (L + R) >> 1)) <= k) R = M; else L = M + 1;
    static PII pos = kth(L);
    For(i, pos.x, pos.y) putchar(s[i]);

    return 0;
}
//《秋夜曲》
//作者:王维
//桂魄初生秋露微,轻罗已薄未更衣。
//银筝夜久殷勤弄,心怯空房不忍归。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325702894&siteId=291194637