SP1812 LCS2 - Longest Common Substring II

Description:

\(n\) 个长度 \(\le 10^5\) 的字符串,求它们最长公共子串。\(n\le 10\)

Solution:

把第一个字符串的 \(SAM\) 建出来,然后其他串在上跑,跑到一个点记录当前匹配的最长子串,但最后答案是和每个点匹配的最长中最小的去取 \(min\),所以在自动机上跑的时候维护一个 \(lcs[x]\)\(slcs[x]\) 分别表示当前正在跑的串在这个节点匹配到的最长子串长度和之前所有的最小值,由于一个点匹配上了,它所有祖先都会匹配到,所以每跑完后每个点的 \(lcs[x]\) 要和它的儿子取 \(max\) 同时和自己的 \(maxlen\)\(min\) ,此时 \(slcs\) 再和 \(lcs[x]\)\(min\) ,别忘记处理完一个串后要清空 \(lcs[x]\)

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>

typedef long long LL;
typedef unsigned long long uLL;

#define inline __inline__ __attribute__ ((always_inline)) 
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define GO cerr << "GO" << endl;

using namespace std;

inline void proc_status()
{
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
}

template<class T> inline T read() 
{
    register int x = 0; register int f = 1; register char c;
    while (!isdigit(c = getchar())) if (c == '-') f = -1;
    while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
    return x * f;
}

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

const int maxN = (int) 1e5;

int len[12], n;
int rk[maxN * 2], lcs[maxN * 2], slcs[maxN * 2];
char str[12][maxN + 2];

namespace SAM
{
    int Ncnt, last;

    struct Status 
    { int len, link, ch[26]; } st[maxN * 2];

    inline void init()
    { st[0].len = 0, st[0].link = -1, Ncnt = 0; }

    inline void insert(char ch)
    {
        int c = ch - 'a';
        int cur = ++Ncnt;
        int p = last;
        st[cur].len = st[last].len + 1;
        while (p != -1 and !st[p].ch[c])
        {
            st[p].ch[c] = cur;
            p = st[p].link;
        }
        if (p == -1)
            st[cur].link = 0;
        else 
        {
            int q = st[p].ch[c];
            if (st[q].len == st[p].len + 1)
                st[cur].link = q;
            else 
            {
                int clone = ++Ncnt;
                st[clone] = st[q];
                st[clone].len = st[p].len + 1;
                while (p != -1 and st[p].ch[c] == q)
                {
                    st[p].ch[c] = clone;
                    p = st[p].link;
                }
                st[q].link = st[cur].link = clone;
            }
        }
        last = cur;
    }
} 
using namespace SAM;

inline void Input()
{
    while (scanf("%s", str[++n] + 1) != EOF)
        len[n] = strlen(str[n] + 1);
    n--;
}

inline void Init()
{
    init();
    for (register int i = 1; i <= len[1]; ++i)
        insert(str[1][i]);

    static int buc[maxN * 2];

    for (register int i = 1; i <= Ncnt; ++i) buc[st[i].len]++;
    for (register int i = 1; i <= Ncnt; ++i) buc[i] += buc[i - 1];
    for (register int i = 1; i <= Ncnt; ++i) rk[buc[st[i].len]--] = i;

    for (register int i = 0; i <= Ncnt; ++i) slcs[i] = (int) 1e5 + 1;
}

inline void Solve()
{
    for (int t = 2; t <= n; ++t)
    {
        for (register int i = 0; i <= Ncnt; ++i)
            lcs[i] = 0;
        int cur = 0, L = 0;
        for (register int i = 1; i <= len[t]; ++i)
        {
            int c = str[t][i] - 'a';
            while (cur != -1 and !st[cur].ch[c])
            {
                cur = st[cur].link;
                if (cur != -1)
                    L = st[cur].len;
            }
            if (cur == -1)
                cur = 0;
            else 
            {
                L++;
                cur = st[cur].ch[c];
                chkmax(lcs[cur], L);
            }
        }
        for (register int i = Ncnt; i >= 1; --i)
        {
            int cur = rk[i];
            chkmin(lcs[cur], st[cur].len);
            chkmin(slcs[cur], lcs[cur]);
            if (cur) chkmax(lcs[st[cur].link], lcs[cur]);
        }
    }
    int ans = 0;
    for (register int i = 1; i <= Ncnt; ++i)
        chkmax(ans, slcs[i]);
    cout << ans << '\n';
}

int main() 
{
#ifndef ONLINE_JUDGE
    freopen("xhc.in", "r", stdin);
    freopen("xhc.out", "w", stdout);
#endif

    Input();

    Init();

    Solve();

    return 0;
}

转载于:https://www.cnblogs.com/cnyali-Tea/p/11481866.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值