[ICPC2016上海F] Mr. Panda and Fantastic Beasts - SAM

Description

给定 N 个串,求第一个串的子串中不在后面几个串中出现的最短子串,最小化字典序。

Solution

对第一个串建立 SAM,把后面的所有串扔上去跑,打标记(封禁某个结点表示的所有长于某个值的子串)

这样很容易求出答案的长度,问题是怎么构造字典序最小

最后用了个很暴力的方法,对于每个结点,如果没有被封禁并且包含等于目标长度的串,我们就拿去刷一下答案

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;

#define reset(x) memset(x, 0, sizeof x)
int caseid = 0;

struct SAM
{
    int len[N];
    int ch[N][26];
    int fa[N];
    int ind;
    int last;
    int t[N];
    int a[N];
    int cnt[N];
    int f[N];
    int tag[N];
    int vis[N];
    int from[N];
    int minf;
    string ans;
    string str;

    void init()
    {
        reset(len);
        reset(ch);
        reset(fa);
        reset(t);
        reset(a);
        reset(cnt);
        memset(f, 0, sizeof f);
        reset(tag);
        reset(vis);
        reset(from);
        ind = last = 1;
        minf = 1e9;
        ans = "";
    }

    void extend(int id)
    {
        int cur = ++ind;
        int p;
        len[cur] = len[last] + 1;
        cnt[cur] = 1;
        for (p = last; p && !ch[p][id]; p = fa[p])
            ch[p][id] = cur;
        if (!p)
            fa[cur] = 1;
        else
        {
            int q = ch[p][id];
            if (len[q] == len[p] + 1)
                fa[cur] = q;
            else
            {
                int tmp = ++ind;
                len[tmp] = len[p] + 1;
                for (int i = 0; i < 26; i++)
                    ch[tmp][i] = ch[q][i];
                fa[tmp] = fa[q];
                for (; p && ch[p][id] == q; p = fa[p])
                    ch[p][id] = tmp;
                fa[cur] = fa[q] = tmp;
            }
        }
        last = cur;
    }

    void transtag()
    {
        memset(t, 0, sizeof t);
        for (int i = 1; i <= ind; i++)
            t[len[i]]++;
        for (int i = 1; i <= ind; i++)
            t[i] += t[i - 1];
        for (int i = 1; i <= ind; i++)
            a[t[len[i]]--] = i;
        for (int i = ind; i >= 1; i--)
            f[fa[a[i]]] = max(f[fa[a[i]]], f[a[i]]);
        for (int p = 1; p <= ind; p++)
            if (f[p] >= len[p])
                f[p] = 1e9;
            else
                f[p] = max(len[fa[p]] + 1, f[p] + 1);
        minf = 1e9;
        for (int i = 1; i <= ind; i++)
            if (f[i] < minf)
                minf = f[i];
        for (int i = 1; i <= ind; i++)
            if (f[i] <= minf)
                f[i] = 0;
            else
                f[i] = 1;
        for (int i = 1; i <= ind; i++)
            tag[fa[a[i]]] = max(tag[fa[a[i]]], tag[a[i]]);
    }

    void go(const string &s)
    {
        int n = s.length();
        int p = 1;
        int tmp = 0;
        for (int i = 0; i < n; i++)
        {
            while (p > 1 && ch[p][s[i] - 'a'] == 0)
                p = fa[p], tmp = len[p];
            if (ch[p][s[i] - 'a'])
                ++tmp, p = ch[p][s[i] - 'a'];
            f[p] = max(f[p], tmp);
        }
    }

    void maketag(const string &s)
    {
        int n = s.length();
        int p = 1;
        for (int i = 0; i < n; i++)
        {
            p = ch[p][s[i] - 'a'];
            tag[p] = i + 1;
        }
    }

    void printans()
    {
        for (int i = 1; i <= ind; i++)
        {
            if (len[fa[i]] < minf && minf <= len[i])
            {
                int r = tag[i];
                int l = r - minf + 1;
                if (f[i])
                    continue;
                string tmp = str.substr(l - 1, r - l + 1);
                if (ans == "" || ans > tmp)
                    ans = tmp;
            }
        }
        if (ans != "")
            cout << ans << endl;
        else
            cout << "Impossible" << endl;
    }
} sam;

void solve()
{
    ++caseid;
    int n;
    cin >> n;
    sam.init();

    string s;
    cin >> s;
    string s0 = s;
    sam.str = s;
    for (int i = 0; i < s.size(); i++)
    {
        sam.extend(s[i] - 'a');
    }
    for (int i = 1; i < n; i++)
    {
        cin >> s;
        sam.go(s);
    }
    sam.maketag(s0);
    sam.transtag();
    cout << "Case #" << caseid << ": ";
    sam.printans();
}

signed main()
{
    ios::sync_with_stdio(false);

    int t;
    cin >> t;
    while (t--)
        solve();
}

相关文章: