POJ-1226 Substrings(后缀数组)
题目:
Substrings
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 13990 Accepted: 4952
Description
You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.
Input
The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.
Output
There should be one line per test case containing the length of the largest string found.
Sample Input
2
3
ABCD
BCDFF
BRCD
2
rose
orchid
Sample Output
2
2
题意:
求n个串或他们的翻转串中的最长公共子串
把n个串以及翻转串连起来,中间用特殊字符隔开,求出后缀数组,然后二分判定公共子串长度
AC代码:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<complex>
#include<queue>
#include <map>
#define T 21111
using namespace std;
char s[T];
int a[105];
int t1[T],t2[T],cc[T],x[T],sa[T],rank[T],height[T];
int len;
int vis[105];
char subs[105];
map<int,int> mp;
bool cmp(int *y,int a,int b,int k)
{
int a1=y[a];
int b1=y[b];
int a2=a+k>=len ? -1:y[a+k];
int b2=b+k>=len ? -1:y[b+k];
return a1==b1 && a2==b2;
}
int make_sa()
{
int *x=t1,*y=t2;
int m=255;
for(int i=0; i<m; i++) cc[i]=0;
for(int i=0; i<len; i++) ++cc[x[i]=s[i]];
for(int i=1; i<m; i++) cc[i]+=cc[i-1];
for(int i=len-1; i>=0; i--) sa[--cc[x[i]]]=i;
for(int k=1; k<=len; k<<=1)
{
int p=0;
for(int i=len-k; i<len; i++) y[p++]=i;
for(int i=0; i<len; i++)
if( sa[i]>=k ) y[p++]=sa[i]-k;
for(int i=0; i<m; i++) cc[i]=0;
for(int i=0; i<len; i++) ++cc[x[y[i]]];
for(int i=1; i<m; i++) cc[i]+=cc[i-1];
for(int i=len-1; i>=0; i--) sa[--cc[x[y[i]]]]=y[i];
swap(x,y);
m=1; x[sa[0]]=0;
for(int i=1; i<len; i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1:m++;
if( m>=len ) break;
}
}
void make_height()
{
for(int i=0; i<len; i++) rank[sa[i]]=i;
height[0]=0;
int k=0;
for(int i=0; i<len; i++)
{
if(!rank[i]) continue;
int j=sa[rank[i]-1];
if(k) k--;
while(s[i+k]==s[j+k]) k++;
height[rank[i]]=k;
}
}
bool check(int k,int n)
{
int sum=1,flag=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<len;i++){
int z=sa[i];
map<int,int>::iterator itea;
itea=mp.lower_bound(z);
int y=itea->second;
int lst=itea->first;
if(height[i]<k||s[sa[i]]=='$'||sa[i]+k>lst){
sum=1;
memset(vis,0,sizeof(vis));
vis[y]++;
continue;
}
if(!vis[y]){
vis[y]++;
sum++;
}
if(sum==n) return true;
}
return false;
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int m=0,maxn=0;
mp.clear();
for(int i=0;i<n;i++){
scanf("%s",subs);
int y=strlen(subs);
for(int j=0;j<y;j++){
s[j+m]=subs[j];
}
s[m+y]='$';
m+=y+1;
mp[m-1]=i;
maxn=max(maxn,y);
for(int j=0;j<y;j++){
s[j+m]=subs[y-j-1];
}
s[m+y]='$';
m+=y+1;
mp[m-1]=i;
}
len=m-1;
s[m]='\0';
make_sa();
make_height();
int l=1,r=maxn+1;
while(l!=r){
int mid=(l+r)/2;
if(check(mid,n)) l=mid+1;
else r=mid;
}
cout<<r-1<<endl;
}
return 0;
}