zoukankan      html  css  js  c++  java
  • [ICPC2016上海F] Mr. Panda and Fantastic Beasts

    [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();
    }
    
  • 相关阅读:
    L1-012 计算指数
    L1-011 A-B
    L1-010 比较大小
    Django--登录
    Django--跨域设置
    Django--视图装饰器
    Django--URL配置
    Django--多数据库
    Django--channels
    Django--日志
  • 原文地址:https://www.cnblogs.com/mollnn/p/14667881.html
Copyright © 2011-2022 走看看