[HDU2328]Corporate Identity(后缀数组)

时间:2023-03-09 01:55:58
[HDU2328]Corporate Identity(后缀数组)

传送门

求 n 个串的字典序最小的最长公共子串。

和 2 个串的处理方法差不多。

把 n 个串拼接在一起,中间连上一个没有出现过的字符防止匹配过界。

求出 height 数组后二分公共子串长度给后缀数组分组。

然后 check,每一组中是否所有的字符串都包含。

直接遍历 sa 数组,第一个满足的结果就是字典序最小的。

——代码

 #include <cstdio>
#include <cstring>
#include <iostream>
#define N 900005
#define M 4001 int n, len, m, start;
int buc[N], x[N], y[N], sa[N], rank[N], height[N], belong[N];
char s[N], a[M];
bool f[M]; inline void build_sa()
{
int i, k, p;
for(i = ; i < m; i++) buc[i] = ;
for(i = ; i < len; i++) buc[x[i] = s[i]]++;
for(i = ; i < m; i++) buc[i] += buc[i - ];
for(i = len - ; i >= ; i--) sa[--buc[x[i]]] = i;
for(k = ; k <= len; k <<= )
{
p = ;
for(i = len - ; i >= len - k; i--) y[p++] = i;
for(i = ; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
for(i = ; i < m; i++) buc[i] = ;
for(i = ; i < len; i++) buc[x[y[i]]]++;
for(i = ; i < m; i++) buc[i] += buc[i - ];
for(i = len - ; i >= ; i--) sa[--buc[x[y[i]]]] = y[i];
std::swap(x, y);
p = , x[sa[]] = ;
for(i = ; i < len; i++)
x[sa[i]] = y[sa[i - ]] == y[sa[i]] && y[sa[i - ] + k] == y[sa[i] + k] ? p - : p++;
if(p >= len) break;
m = p;
}
} inline void build_height()
{
int i, j, k = ;
for(i = ; i < len; i++) rank[sa[i]] = i;
for(i = ; i < len; i++)
{
if(!rank[i]) continue;
if(k) k--;
j = sa[rank[i] - ];
while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++;
height[rank[i]] = k;
}
} inline bool check(int k)
{
int i, cnt = ;
memset(f, , sizeof(f));
f[belong[sa[]]] = ;
for(i = ; i < len; i++)
if(height[i] >= k)
{
if(!f[belong[sa[i]]]) cnt++;
f[belong[sa[i]]] = ;
if(cnt == n)
{
start = sa[i];
return ;
}
}
else
{
memset(f, , sizeof(f));
f[belong[sa[i]]] = ;
cnt = ;
}
return ;
} int main()
{
int i, j, l, r, mid, leng;
while(scanf("%d", &n) && n)
{
len = ;
m = ;
memset(belong, , sizeof(belong));
for(i = ; i <= n; i++)
{
scanf("%s", a);
for(j = ; a[j] ^ '\0'; j++) s[len++] = a[j];
s[len++] = '#';
belong[len] = ;
}
len--;
build_sa();
build_height();
for(i = ; i < len; i++) belong[i] += belong[i - ];
l = , r = len, leng = , start = -;
while(l <= r)
{
mid = (l + r) >> ;
if(check(mid)) leng = mid, l = mid + ;
else r = mid - ;
}
if(leng && start ^ -)
{
for(i = start; i < start + leng; i++) putchar(s[i]);
putchar('\n');
}
else puts("IDENTITY LOST");
}
return ;
}