Description

求在两个给定字符串中各只出现一次的最短的公共子串。

Solution

对两个给定串建立广义 SAM,对每个结点,分别记录源于各个串的 \(endpos\) 集合的大小 \(cnt[i][0], cnt[i][1]\)

遍历所有节点 \(p\),若 \(cnt[p][0] = 1 \and cnt[p][1] = 1\) 则该点合法,用它的 \(minlen\) 更新答案

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2000005;
struct SAM
{
    int len[N], ch[N][26], fa[N], ind, last, cnt[N][2], a[N], t[N];
    SAM()
    {
        ind = last = 1;
    }
    inline int extend(int id)
    {
        if(ch[last][id] && len[last]+1==len[ch[last][id]]) return ch[last][id]; //!
        int cur = (++ ind), p, tmp, flag = 0; //!
        len[cur] = len[last] + 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
            {
                if(p==last) flag=1; //!
                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;
        return flag ? tmp : cur;//!
    }
    void extend(string s, int id)
    {
        for(int i=0; i<s.length(); i++)
        {
            last = extend(s[i]-'a');
            cnt[last][id]=1;
        }
        last = 1;
    }
    void calc()
    {
        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 id=0; id<2; id++) for(int i=ind; i>=1; --i) cnt[fa[a[i]]][id]+=cnt[a[i]][id];
        cnt[1][0] = cnt[1][1] = 0;
    }
    int solve()
    {
        int ans=1e9;
        for(int i=1;i<=ind;i++) if(cnt[i][0]==1 && cnt[i][1]==1) ans=min(ans,len[fa[i]]+1);
        return ans > 1e8 ? -1 : ans;
    }
} sam;

signed main()
{
    ios::sync_with_stdio(false);
    int n;
    string str;
    for(int i=1; i<=2; i++)
    {
        cin>>str;
        sam.extend(str,i-1);
    }
    sam.calc();
    cout<<sam.solve()<<endl;
}




相关文章:

  • 2022-12-23
  • 2021-06-13
  • 2022-12-23
  • 2022-12-23
  • 2021-09-07
  • 2021-09-15
  • 2021-11-08
  • 2021-12-30
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-11-25
  • 2022-12-23
  • 2022-12-23
  • 2022-03-04
相关资源
相似解决方案