题目大意:给出n个字符串,求最大的i使得第i个字符串存在一个比i小的j字符串j,j字符串不是i字符串的子串
解题思路:如果直接用KMP,TLE,优化一下,先预处理相邻的字符串,如果j是k的子串,那么只需要判断k串(因为k串一旦是i串的子串,那么j串一定是i串的子串),一定要先标记所有串为主串,从小到大更新,子串标记为false,反过来标记达不到优化目的
#include <bits/stdc++.h>
using namespace std;
const int maxn = 510;
const int maxm = 2010;
char s[maxn][maxm];
int NEXT[maxm];///NEXT[i]表示既是模式串前i个字母的前缀又是又是模式串前i个字母的后缀的串的最长长度
bool exist[maxn];///exist[i]为1表示i串没有被匹配(i串不是i+1串的子串),0表示i串被匹配了子串
/**串S中T出现的次数,S叫做主串,T叫做模式串**/
void getNext(char *T)///求模式串的NEXT
{
int j = 0;
int k = -1;
NEXT[0] = -1;
int tlen = strlen(T);
while(j < tlen)
if(k == -1 || T[j] == T[k])
NEXT[++j] = ++k;
else
k = NEXT[k];
}
/**
返回模式串T在主串S中出现的次数
**/
int KMP_Count(char *S,char *T)
{
int ans = 0;
int i, j = 0;
int tlen = strlen(T);
int slen = strlen(S);
if(slen == 1 && tlen == 1)
{
if(S[0] == T[0])
return 1;
else
return 0;
}
getNext(T);
for(i = 0; i < slen; i++)
{
while(j > 0 && S[i] != T[j])
j = NEXT[j];
if(S[i] == T[j])
j++;
if(j == tlen)
{
ans++;
j = NEXT[j];
}
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
int cas = 1;
while(t--)
{
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%s",s[i]);
memset(exist,true,sizeof(exist));
for(int i = 2; i <= n; i++)
{
if(KMP_Count(s[i],s[i-1]))///如果s[i-1]是s[i]的子串
exist[i-1] = false;
}
int flag = 0;///表示结束,找到j串不是i串的子串
for(int i = n; i >= 1&&!flag; i--)
for(int j = 1; j < i&&!flag; j++)
if(exist[j])///只需要找和主串是否不匹配
if(!KMP_Count(s[i],s[j]))
flag = i;
if(flag)
printf("Case #%d: %d\n",cas++,flag);
else
printf("Case #%d: -1\n",cas++);
}
return 0;
}