题意:给出1-10个长度为60的字符串,求出最长的公共子串(长度不能小于3),如果有多个一样长的,输出字典序最短的。
解法:想到kmp时,自己第一反应枚举第一个串的所有子串,在其他所有串中走一遍kmp,复杂度为10*60*60*60,但是发现只需枚举第一个串后缀就可以,每次枚举记录在所有串能走最远中走的最短的那个长度。这样复杂度就成了10*60*60,0ms AC。
代码:
/****************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
using namespace std;
#define eps 1e-8
typedef long long LL;
char str[10][61];
int n;
char ans[61];
char tool[61];
int out=0;
char Next[61];
void getnext()
{
int i=0;
int j=Next[0]=-1;
int len=strlen(tool);
while(i<len)
{
while(j!=-1&&tool[i]!=tool[j]) j=Next[j];
Next[++i]=++j;
}
}
int kmp(int k)
{
int i=0,j=0;
int res=0;
for(int i=0; i<60; i++)
{
while(j!=-1&&str[k][i]!=tool[j]) j=Next[j];
j++;
res=max(res,j);
}
return res;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d",&n);
memset(ans,0,sizeof ans);
memset(tool,0,sizeof tool);
out=0;
for(int i=0; i<n; i++)
scanf("%s",str[i]);
int len=strlen(str[0]);
for(int i=0; i<len; i++)
{
memset(tool,0,sizeof tool);
strncpy(tool,str[0]+i,len-i);
int ma=60;
getnext();
for(int j=1; j<n; j++)
ma=min(ma,kmp(j));
if(ma>out)
{
out=ma;
strncpy(ans,tool,out);
ans[out]=0;
}
else if(ma==out)
{
if(strcmp(ans,tool)>0)
strncpy(ans,tool,out);
ans[out]=0;
}
}
if(strlen(ans)<3)printf("no significant commonalities\n");
else printf("%s\n",ans);
}
return 0;
}