E - Bazinga HDU - 5510
原题意思是给n个字符串,如果第i的字符串以前的字符串有一个及以上不是它子串的话那么这个i是好的,要求找到最大的i。
找子串的话直接用kmp。
再之后就是枚举,最简单直接想到暴力,对于第i个字符串,枚举前i-1个字符串,然后再枚举i,但是这个肯定不行,超时。
要更快的算法,我们发现找第i个字符串时判断第j个是不是它的子串,那之后j以前的字符串中如果有j的子串的就不用判断了,因为j都判断过了,如果j是i的子串,那么j的子串也是i的子串,如果j不是i的子串那也不用判断其他的了。这个操作我用vector实现如果j是i的子串,删除j,加入i,如果不是,加入i,更新答案这题就写完了。其实还是有特例可以卡掉这个,所有的字符串都没有子串关系,长度都为最长,但样例也没这样刁难,本身也是个铜牌题,就这么做吧,以下是代码。
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int t,n;
char s[507][2007],net[2007];
vector<int >ho;
void getnext(char *ptr)
{
int i,n,k;
n=strlen(ptr);
k=-1;
net[0]=-1;
i=0;
while(i<n)
{
if(k==-1 || ptr[i]==ptr[k])// k=-1用于指针i的移动 结合k=next[k]看
{
i++;
k++;
net[i]=k;
}
else k=net[k];
}
}
int kmp(char *a,char *b)//匹配ab两串,a为父串
{
int i=0,j=0;
int len1=strlen(a);
int len2=strlen(b);
getnext(b);
while(i<len1&&j<len2)
{
if(j==-1||a[i]==b[j])
++i,++j;
else
j=net[j];
}
if(j==len2)
return i-j;
else
return -1;
}
int main(){
scanf("%d",&t);
int p=0;
while(t--){
ho.clear();
p++;
int ok=0,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s[i]);
}
for(int i=1;i<=n;i++){
if(i==1){
ho.push_back(1);
}
else{
for(int j=0;j<ho.size();j++){
if(kmp(s[i],s[ho[j]])==-1){
ans=i;
ok=1;
}
else{
ho.erase(ho.begin()+j);
j--;
}
}
ho.push_back(i);
}
}
if(ok==1){
printf("Case #%d: %d\n",p,ans);
}
else{
printf("Case #%d: -1\n",p);
}
}
return 0;
}