题意:给出N个字符串,求出最长的子串,在每个字符串中都出现。
思路:二分答案,对height进行数组,判断即可。
代码如下:
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
static const int maxn =1000100;
int rk[maxn],sa[maxn],height[maxn];
int a[maxn],b[maxn],cont[200000];
//待排序字符串为r,长度为n,范围r[0] - r[n-1],值额范围0 - n-1.
//字符集为m,范围1 - m;
void radix_sort(int * r, int *a, int *b, int n, int m){//将a按照r进行基数排序,储存到b,长度为n,字符集为m
memset(cont,0,sizeof(cont));
for(int i = 0; i < n; ++i) ++cont[r[a[i]]];
for(int i = 1; i <= m; ++i) cont[i] += cont[i-1];
for(int i = n -1; i >= 0; --i) b[--cont[r[a[i]]]] = a[i];
}
void calc_sa(int*r, int n, int m){
for(int i = 0; i < n; ++i) rk[i] =i;
radix_sort(r,rk,sa,n,m);
rk[sa[0]] = 0;
for(int i = 1; i < n; ++i)
rk[sa[i]]= rk[sa[i-1]] +(r[sa[i]]!=r[sa[i-1]]);
for(int i = 0; 1<<i< n; ++i){
for(int j = 0; j < n; ++j){
a[j] = rk[j]+1;
b[j] = j + (1<<i) >=n? 0: rk[j + (1<<i)] + 1;
sa[j] = j;
}
radix_sort(b,sa,rk,n,n);
radix_sort(a,rk,sa,n,n);
rk[sa[0]] = 0;
for(int j = 1; j < n; ++j){
rk[sa[j]] = rk[sa[j-1]] + (a[sa[j-1]] != a[sa[j]] || b[sa[j-1]] != b[sa[j]]);
}
}
}
void calc_height(int * r,int n) {//计算height
for(int i = 0 ; i < n; ++i) rk[sa[i]] = i;
int h = 0;
for(int i = 0; i < n; ++i){
h = h == 0?0: h - 1;
if(rk[i]!= 0)
while(r[i + h] == r[sa[rk[i]-1] + h]) h++;
height[rk[i]] = h;
}
}
int r[1010];
char str[1010];
int p[1010];
int n,N,pos,len,T;
set<int> record;
bool judge(int mid)
{
for(int i = 0; i < n; ++i){
if(height[i] < mid){
record.clear();
continue;
}
record.insert(sa[i]/(len+1));
record.insert(sa[i-1]/(len+1));
if(record.size() == N){
pos = sa[i];
return true;
}
}
return false;
}
int main(void)
{
//freopen("input.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d",&N);
n = 0;
for(int i = 0; i < N; ++i){
scanf("%s",str);
for(int j = 0; str[j];++j)
r[n++] = str[j];
r[n++] = 1000+i;
}
len = strlen(str);
calc_sa(r,n,6000);
calc_height(r,n);
int lb = 0, ub = len + 1;
while(lb + 1 < ub){
int mid = (lb + ub) >> 1;
if(judge(mid)) lb = mid;
else ub = mid;
}
//printf("%d\n",lb);
if(lb < 3)
puts("no significant commonalities");
else{
for(int i = 0; i < lb; ++i)
putchar(r[pos+i]);
putchar('\n');
}
}
return 0;
}