大致题意:
就是求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; }
时间: 2024-10-25 02:15:40