题意:给定 n 个字符串,标号 1~n,找出标号最大的字符串 i,使 1~i 中存在一个字符串不是 i 的子串。
很容易想到 KMP,如果直接搞会超时,那么可以从头开始遍历主串,记录满足条件的串,最后从后找第一个满足条件的就可以。
每次遍历子串时,如果找到字符串 j 是 i 的子串,就把 j 标记一下,再往后就不需要对 j 进行 KMP。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
using namespace std;
int nextt[505][2005];
char s[505][2005];
int f[505]; //f[i]=1表示i是后面某个串的子串
int ans[505]; //如果字符串i满足题意则ans[i]=1,最后从大到小遍历i即可
void kmp_pre(char x[],int m,int nextt[]){
int i, j;
j = nextt[0] = -1;
i = 0;
while(i < m){
while(-1!=j && x[i]!=x[j])
j = nextt[j];
nextt[++i] = ++j;
}
}
int KMP_Index(char x[], int m, char y[], int n, int k){
int i = 0, j = 0;
//kmp_pre(x, m, nextt);
while(i < n && j < m){
if(j == -1 || y[i] == x[j]){
i++; j++;
}
else
j = nextt[k][j];
}
if(j == m)
return i-m;
else
return -1;
}
int main(){
//freopen("a.txt", "r", stdin);
int t; cin >> t;
for(int cas = 1; cas <= t; cas++){
memset(f, 0, sizeof(f));
memset(ans, 0, sizeof(ans));
int n;
scanf("%d", &n);
//求next
for(int i = 0; i < n; i++){
scanf("%s", s[i]);
kmp_pre(s[i], strlen(s[i]), nextt[i]);
}
int flag = 0;
for(int i = 1; i < n; i++){
for(int j = 0; j < i; j++){
if(!f[j]){
int k = KMP_Index(s[j], strlen(s[j]), s[i], strlen(s[i]), j);
if(k!=-1) f[j] = 1;
else{
flag = 1;
}
}
}
if(flag){
ans[i] = 1;
flag = 0;
}
}
for(int i = n-1; i >= 0; i--){
if(ans[i]){
printf("Case #%d: %d\n", cas, ++i);
break;
}
if(i==0) printf("Case #%d: -1\n", cas);
}
}
return 0;
}