Description
给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
任务:
l 读入单词
l 计算最长公共子串的长度
l 输出结果
Input
文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。
Output
仅一行,一个整数,最长公共子串的长度。
题解
今天遇到一题后缀数组(正解 后缀自动机——一定要掌握的看家本领),作为复习就又写了道的裸题。
直接将所有串合在一起,二分答案的长度,按height数组分组判断即可。
一定注意:不能写用rank做变量名!!!
一定注意:不能写用rank做变量名!!!
一定注意:不能写用rank做变量名!!!
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 10010
#define rep(i,x,y) for(int i = x; i <= y;i++)
char s[N],str[2010];
int sa[N],t[N],t1[N],c[N];
void build(int n)
{
int *x = t,*y = t1,m = 150;
rep(i,0,m-1) c[i] = 0;
rep(i,0,n-1) c[x[i] = s[i]]++;
rep(i,1,m-1) c[i] += c[i-1];
for(int i = n-1;i >= 0;i--) sa[--c[x[i]]] = i;
for(int k = 1;k <= n;k <<= 1)
{
int p = 0;
for(int i = n-k;i < n;i++) y[p++] = i;
rep(i,0,n-1) if(sa[i] >= k) y[p++] = sa[i]-k;
rep(i,0,m-1) c[i] = 0;
rep(i,0,n-1) c[x[y[i]]] ++;
rep(i,1,m-1) c[i] += c[i-1];
for(int i = n-1;i >= 0;i--) sa[--c[ x[y[i]] ]] = y[i];
swap(x,y);
p = 1;x[sa[0]] = 0;
rep(i,1,n-1)
x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k] ? p-1:p++;
if(p >= n) break;
m = p;
}
}
int Rank[N],height[N];
void get_height(int n)
{
int k = 0;
rep(i,0,n-1) Rank[sa[i]] = i;
rep(i,0,n-1)
{
if(k) k--;
int j = sa[Rank[i]-1];
while(s[i+k] == s[j+k]) k++;
height[Rank[i]] = k;
}
}
int n,pos;
bool have[7],flag;
int belong[N];
/*
bool check(int k)
{
for(int i = 1;i <= pos;i++)
if(height[i] < k || i == pos)
{
flag = true;
for(int j = 1;j <= n;j++)
if(!have[j]) {flag = false;break;}
if(flag) return true;
memset(have,false,sizeof(have));
}
else have[belong[ sa[i] ]] = have[belong[sa[i-1]]] = true;
return false;
}*/
bool check(int k)
{
for(int la=1,i=1;i<=pos;i++)
{
if(height[i]<k || i==pos)
{
for(int j=1;j<=n;j++) have[j]=0;
for(int j=la;j<=i-1;j++)have[belong[sa[j]]]=1;
int flag=0;
for(int j=1;j<=n;j++)if(have[j]==0){flag=1;break;}
if(!flag)return 1;
la=i;
}
}
return 0;
}
int len[10];
int main()
{
scanf("%d",&n);
int R = -1;
pos = 0;
for(int i = 1;i <= n;i++)
{
scanf("%s",str);
len[i] = strlen(str);
R = max(R,len[i]);
for(int j = 0;j < len[i];j++)
{
belong[pos] = i;
s[pos++] = str[j];
}
s[pos++] = '#'+i;
}
s[pos] = ' ';
build(pos);
get_height(pos);
int ans = 0,L = 0;
while(L <= R)
{
int mid = (L+R)>>1;
if(check(mid)){L = mid+1;ans = mid;}
else R = mid-1;
}
printf("%d\n",ans);
return 0;
}