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;
}