大致题意:
就是求k个长度为60的字符串的最长连续公共子串,2<=k<=10
规定:
1、 最长公共串长度小于3不输出
2、 若出现等长的最长的子串,则输出字典序最小的串
思路:和POJ-3450-Corporate Identity一样二分+枚举,但是直接暴力也0ms
//192 KB 0 ms 题目太水,我就把POJ3450的代码改了几句话
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char str[4010][210];
char minstr[210],tmp[210];
int next[210];
int lens[4010];
int n;
void getnext()
{
next[0]=-1;
int i=0,j=-1;
while(tmp[i]!=0){
while(j>-1&&tmp[i]!=tmp[j])
j=next[j];
j++;
i++;
next[i]=j;
}
}
bool KMP()
{
getnext();
int lenm=strlen(tmp);
for(int k=1;k<=n;k++){
int i=0,j=0;
while(i<lens[k]&&j<lenm){
if(j==-1||str[k][i]==tmp[j]){
i++;
j++;
}
else j=next[j];
}
if(j!=lenm) return false;
}
return true;
}
bool ok(int x)
{
int len=strlen(minstr);
for(int i=0;i<=len-x;i++){
strncpy(tmp,minstr+i,x);
tmp[x]='\0';
if(KMP()) return true;
}
return false;
}
int main()
{
int _;
scanf("%d",&_);
while(_--){
scanf("%d",&n);
int minn=(1<<30);
for(int i=1;i<=n;i++) {
scanf("%s",str[i]);
lens[i]=strlen(str[i]);
if(minn>lens[i]){
minn=lens[i];
strcpy(minstr,str[i]);
}
}
int lb=0,ub=minn+1;
while(ub-lb>1){
int mid=(lb+ub)/2;
if(ok(mid)) lb=mid;
else ub=mid;
}
char ans[210],first=1;
for(int i=0;lb>=3&&i<=minn-lb;i++){
strncpy(tmp,minstr+i,lb);
tmp[lb]='\0';
if(KMP()){
if(first) {
first=0;
strcpy(ans,tmp);
}
else {
if(strcmp(ans,tmp)>0)
strcpy(ans,tmp);
}
}
}
if(lb>=3) printf("%s\n",ans);
else printf("no significant commonalities\n");
}
return 0;
}