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 orchidSample Output
2 2给你N个字符串,要你求这样一个最长子串的长度,要求这个子串在每个原始串中或原始串的逆串中都出现过一次.输出该串长度即可.
这里可以暴力做也可以使用KMp或者后缀数组
暴力代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<map>
#include<set>
#include<iomanip>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double ld;
const int maxn=105;
char word[maxn][maxn];
int main()
{
char s1[maxn];
char s2[maxn];
int Case,n;
cin>>Case;
int len[maxn];
while(Case--)
{
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
memset(word,0,sizeof(word));
int k=-1,ans=0;
int i,j,m;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%s",word[i]);
len[i]=strlen(word[i]);
if(k==-1||len[i]<len[k])
{
k=i;
}
}
for(i=0; i<len[k]-ans; i++)
{
for(j=i+1+ans; j<=len[k]; j++)
{
for(m=i; m<j; m++)
{
s1[m-i]=word[k][m];
s2[m-i]=word[k][j-m+i-1];
}
s1[m-i]=s2[m-i]='\0';
for(m=0; m<n; m++)
{
if(m!=k)
{
if(!strstr(word[m],s1)&&!strstr(word[m],s2))
break;
}
}
if(m==n)
ans+=1;
else
break;
}
}
cout<<ans<<endl;
}
return 0;
}
后缀数组:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<map>
#include<iomanip>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double ld;
const int maxn=20000+1000;
int nn;//nn是正好超过所有字符串个数一半的整数
int who[maxn];//who[i]表示后缀i属于原始第几个串,如果为0则是人为添加的字符
int ans[maxn];//ans[i]=x表示第i个答案是串s的后缀x
int cnt;//计数答案
int turn=0;
struct SuffixArray
{
int s[maxn];
int sa[maxn],rank[maxn],height[maxn];
int t1[maxn],t2[maxn],c[maxn],n;
int vis[maxn];//需要初始化为0,vis[i]=3表示后缀i出现在了第3轮
void build_sa(int m)
{
int i,*x=t1,*y=t2;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=s[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(int k=1;k<=n;k<<=1)
{
int p=0;
for(i=n-k;i<n;i++) y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=k) y[p++]=sa[i]-k;
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]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
void build_height()
{
int i,j,k=0;
for(i=0;i<n;i++) rank[sa[i]]=i;
for(i=0;i<n;i++)
{
if(k)k--;
j=sa[rank[i]-1];
while(s[i+k]==s[j+k])k++;
height[rank[i]]=k;
}
}
bool check(int limit)
{
int i,j,k,t;
int ss;
for(i=2;i<n;i=j+1)
{
for(;height[i]<limit&&i<n;i++);//i-1是该组下界
for(j=i;height[j]>=limit&&j<n;j++);//j-1是该组上界
if(j-i+1<nn) continue;
turn++; //该轮数+1,表示现在是第turn轮
ss=0;//表示该轮小组目前统计到了ss个串的前缀
for(k=i-1;k<j;k++)
if( (t=who[sa[k]])!=0 )
if(vis[t]!=turn){ ss++;vis[t]=turn; }
if(ss>=nn)
return 1;
}
return 0;
}
void solve()
{
if(nn==1)//注意这里
{
printf("%d\n",(n-1)/2);
return ;
}
memset(vis,0,sizeof(vis));
int min=1,max=n;
while(min<=max)
{
int mid=min+(max-min)/2;
if(check(mid))min=mid+1;
else max=mid-1;
}
printf("%d\n",max);
}
}sa;
int main()
{
char str[1000+100];
int n,T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
nn=n;
sa.n=0;
for(int i=1;i<=n;i++)
{
scanf("%s",str);
int len=strlen(str);
for(int j=0;j<len;j++)
{
sa.s[sa.n+j]=str[j]+200;//注意这里是200,不是100
who[sa.n+j]=i;//归属第几个串
}
sa.s[sa.n+len]=2*i;//注意1 分隔符
who[sa.n+len]=0;//分割符归属0
sa.n=sa.n+len+1;//串长增加
for(int j=0;j<len;j++)//连接逆串
{
sa.s[sa.n+j]=str[len-1-j]+200;
who[sa.n+j]=i;//归属第几个串
}
sa.s[sa.n+len]=2*i-1;//注意2 分割符
who[sa.n+len]=0;//分割符归属0
sa.n=sa.n+len+1;//串长增加
}
sa.s[sa.n-1]=0;
sa.build_sa(328);//注意为什么要用328
sa.build_height();
sa.solve();
}
return 0;
}