CodeForces 427D Match & Catch
SAM
題意
給兩個串,求一個最小子串的長度,使得它是兩個串的公共子串,且在兩個子串中均只出現一次。
思路
對第一個串建自動機,求公共子串就是常規思路,不過跑的時候開個num數組記錄,到一個點說明這個點代表的子串們出現了一次,記錄這個次數,這是第二個串的次數。第一個串的次數在SAM中處理出來,那個endposamu數組。
至於每個狀態,跑到了就說明這個狀態的子串全部都出現過。所以最後取所有endposnum和num都爲1的狀態中minlen最小的值。
代碼
別忘了無解輸出-1
#include<bits/stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
typedef long long LL;
using namespace std;
const int MAXL=10005;
const int MAXS=26;
struct SAM
{
int n=0, len, st;
int maxlen[2*MAXL+10], minlen[2*MAXL+10], trans[2*MAXL+10][MAXS], slink[2*MAXL+10], col[2*MAXL+10], indeg[2*MAXL+10], endposamu[2*MAXL+10], num[2*MAXL+10];
int new_state(int _maxlen, int _minlen, int* _trans, int _slink)
{
n++;
maxlen[n]=_maxlen;
minlen[n]=_minlen;
for(int i=0; i<MAXS; i++)
{
if(_trans==NULL)
trans[n][i]=0;
else
trans[n][i]=_trans[i];
}
slink[n]=_slink;
return n;
}
int add_char(char ch, int u)
{
int c=ch-'a';
int z=new_state(maxlen[u]+1, -1, NULL, 0);
col[z]=1;
int v=u;
while(v!=0&&trans[v][c]==0)
{
trans[v][c]=z;
v=slink[v];
}
if(v==0)
{
minlen[z]=1;
slink[z]=1;
indeg[1]++;
return z;
}
int x=trans[v][c];
if(maxlen[v]+1==maxlen[x])
{
minlen[z]=maxlen[x]+1;
slink[z]=x;
indeg[x]++;
return z;
}
int y=new_state(maxlen[v]+1, -1, trans[x], slink[x]);
col[y]=0;
minlen[x]=maxlen[y]+1;
slink[x]=y;
minlen[z]=maxlen[y]+1;
slink[z]=y;
indeg[y]+=2;
int w=v;
while(w!=0&&trans[w][c]==x)
{
trans[w][c]=y;
w=slink[w];
}
minlen[y]=maxlen[slink[y]]+1;
return z;
}
void init()
{
memset(col, 0, sizeof(col));
memset(indeg, 0, sizeof(indeg));
memset(maxlen, 0, sizeof(maxlen));
memset(minlen, 0, sizeof(maxlen));
memset(trans, 0, sizeof(maxlen));
memset(slink, 0, sizeof(maxlen));
memset(endposamu, 0, sizeof(endposamu));
memset(num, 0, sizeof(num));
n=0;
st=new_state(0, -1, NULL, 0);
}
void getendpos()
{
queue<int> que;
for(int i=st;i<=n;i++)
{
if(indeg[i]==0) que.push(i);
if(col[i]==1) endposamu[i]++;
}
while(!que.empty())
{
int pos=que.front();que.pop();
endposamu[slink[pos]]+=endposamu[pos];
indeg[slink[pos]]--;
if(indeg[slink[pos]]==0) que.push(slink[pos]);
}
}
void addstring(char* s,int len)
{
int la=st;
for(int i=0;i<len;i++)
{
la=add_char(s[i], la);
}
getendpos();
}
int match(char* s, int m)
{
int now=this->st;
for(int i=0;i<m;i++)
{
int k=s[i]-'a';
if(trans[now][k])
{
now=trans[now][k];
num[now]++;
}
else
{
while(!trans[now][k]&&now)
{
now=slink[now];
}
if(!now)
{
now=this->st;
}
else
{
now=trans[now][k];
num[now]++;
}
}
}
int ans=0x3f3f3f3f;
for(int i=this->st;i<=this->n;i++)
{
if(num[i]==1&&endposamu[i]==1)
{
ans=min(ans, minlen[i]);
}
}
if(ans>=0x3f3f3f3f) return -1;
return ans;
}
}sam;
char ss[MAXL*2+7];
int main()
{
sam.init();
scanf("%s", ss);
int n=strlen(ss);
sam.addstring(ss, n);
scanf("%s", ss);
int m=strlen(ss);
cout<<sam.match(ss, m)<<endl;
//system("pause");
return 0;
}