SPOJ PHRASES Relevant Phrases of Annihilation(后缀数组 + 二分)题解
题意:
给\(n\)个串,要你求出一个最长子串\(A\),\(A\)在每个字串至少都出现\(2\)次且不覆盖,问\(A\)最长长度是多少
思路:
后缀数组处理完之后,二分这个长度,可以\(O(n)\)验证可行性,注意是“不覆盖”(英文不好看不懂),随便搞一下就好了。
代码:
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const ull seed = 11;
const int MOD = 1e9 + 7;
using namespace std;
int str[maxn];
int t1[maxn], t2[maxn], c[maxn];
int sa[maxn];
int rk[maxn];
int height[maxn];
bool cmp(int *r, int a, int b, int l){
return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *str, int n, int m){
n++;
int i, j, p, *x = t1, *y = t2;
for(i = 0; i < m; i++) c[i] = 0;
for(i = 0; i < n; i++) c[x[i] = str[i]]++;
for(i = 1; i < m; i++) c[i] += c[i - 1];
for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
for(j = 1; j <= n; j <<= 1){
p = 0;
for(i = n - j; i < n; i++) y[p++] = i;
for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
for(i = 0; i < m; i++) c[i] = 0;
for(i = 0; i < n; i++) c[x[y[i]]]++;
for(i = 1; i < m; i++) c[i] += c[i - 1];
for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = 1; x[sa[0]] = 0;
for(i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j)? p - 1 : p++;
if(p >= n) break;
m = p;
}
int k = 0;
n--;
for(i = 0; i <= n; i++) rk[sa[i]] = i;
for(i = 0; i < n; i++){
if(k) k--;
j = sa[rk[i] - 1];
while(str[i + k] == str[j + k]) k++;
height[rk[i]] = k;
}
}
char s[maxn];
int belong[maxn];
int num[15], pre[15];
int tot;
bool judge(int n){
for(int i = 1; i <= n; i++){
if(num[i] < 2) return false;
}
return true;
}
bool check(int len, int cnt, int n){
memset(num, 0, sizeof(num));
memset(pre, -1, sizeof(pre));
for(int i = 2; i <= cnt; i++){
if(height[i] >= len){
if(pre[belong[sa[i - 1]]] == -1){
num[belong[sa[i - 1]]]++;
pre[belong[sa[i - 1]]] = sa[i - 1];
}
else if(abs(pre[belong[sa[i - 1]]] - sa[i - 1]) >= len){
num[belong[sa[i - 1]]]++;
}
if(pre[belong[sa[i]]] == -1){
num[belong[sa[i]]]++;
pre[belong[sa[i]]] = sa[i];
}
else if(abs(pre[belong[sa[i]]] - sa[i]) >= len){
num[belong[sa[i]]]++;
}
}
else{
if(judge(n)) return true;
memset(num, 0, sizeof(num));
memset(pre, -1, sizeof(pre));
}
}
return judge(n);
}
int main(){
int n;
int T;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
int cnt = 0;
for(int i = 1; i <= n; i++){
scanf("%s", s);
int len = strlen(s);
for(int j = 0; j < len; j++){
belong[cnt] = i;
str[cnt++] = s[j];
}
belong[cnt] = -i;
str[cnt++] = i;
}
cnt--;
str[cnt] = 0;
da(str, cnt, 130);
int l = 1, r = 10000;
int Max = 0;
while(l <= r){
int m = (l + r) >> 1;
if(check(m, cnt, n)){
Max = m;
l = m + 1;
}
else{
r = m - 1;
}
}
printf("%d\n", Max);
}
return 0;
}