题意:对于n个字符串,找到最大的i,满足条件:S1,S2,……,Si-1中至少存在一个字符串不是Si的子串。
1<=N<=500;字符串长度不超过2000.共1~50组数据,1000MS
算法/思路:
KMP即可,先从大到小判断KMP(Si,Si+1),若连续为真,说明Si为Si+1,Si+2,……,Sn的子串;若到某个i为假,说明Si+1满足条件(但未必最大)。注意此时Si+1为Si+2,……,Sn的子串,故Si+1的子串必定为Si+2,……,Sn的子串。
令bound=i+1如果kmp(i,bound)不成立,那么bound满足条件,++bound,否则--i(因为当前Si是bound及以后字符串的子串,没有判断价值),继续进行判断,直到i=1或者bound=n+1,答案为bound-1,复杂度为O(n*length)。
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn=3000; char s[600][maxn]; int next1[maxn][maxn]; int t,n,ans,bound; void ms(int v){ int n=strlen(s[v]);int i=0,j=-1;next1[v][0]=-1; while (i!=n){ if (j!=-1 && s[v][i]!=s[v][j]) j=next1[v][j]; ++i;++j; if (s[v][i]==s[v][j]) next1[v][i]=next1[v][j];else next1[v][i]=j; } } int kmp(int a,int b){ int n=strlen(s[a]),m=strlen(s[b]); int i=0,j=0; while (i<m){ if (s[b][i]==s[a][j]){ ++i;++j; if (j==n) return (i-n+1); } else if (next1[a][j]!=-1) j=next1[a][j]; else {j=0;++i;} } return -1; } int main(){ cin>>t; for (int q=1;q<=t;++q){ cin>>n; for (int i=1;i<=n;++i){ scanf("%s",&s[i]); ms(i); } int i; //for (int i=1;i<=n;++i) //for (int j=i+1;j<=n;++j) cout<<kmp(i,j)<<endl; //cout<<kmp(3,4)<<"asd "<<endl; for (i=n-1;i>=1 && kmp(i,i+1)!=-1;--i); if (i==0) ans=-1;else{ bound=i+1; for (;i>=1 && bound<=n;--i){ while (bound<=n && kmp(i,bound)==-1) ++bound; } ans=bound-1; } printf("Case #%d: %d ",q,ans); } return 0; }