Bazinga
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2672 Accepted Submission(s): 841
Problem Description
Ladies and gentlemen, please sit up straight.
Don't tilt your head. I'm serious.
For n given strings S1,S2,⋯,Sn, labelled from 1 to n, you should find the largest i (1≤i≤n) such that there exists an integer j (1≤j<i) and Sj is not a substring of Si.
A substring of a string Si is another string that occurs in Si. For example, ``ruiz" is a substring of ``ruizhang", and ``rzhang" is not a substring of ``ruizhang".
Input
The first line contains an integer t (1≤t≤50) which is the number of test cases.
For each test case, the first line is the positive integer n (1≤n≤500) and in the following n lines list are the strings S1,S2,⋯,Sn.
All strings are given in lower-case letters and strings are no longer than 2000 letters.
Output
For each test case, output the largest label you get. If it does not exist, output −1.
Sample Input
4
5
ab
abc
zabc
abcd
zabcd
4
you
lovinyou
aboutlovinyou
allaboutlovinyou
5
de
def
abcd
abcde
abcdef
3
a
ba
ccc
Sample Output
Case #1: 4
Case #2: -1
Case #3: 4
Case #4: 3
Source
2015ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)
题目大意:
给你n个字符串,让你找一个最大的i,使得在第i个字符串之前的字符串中,至少有一个不是第i个字符串的子串。
思路:
1、首先对应子串与否的判定方面,直接用KMP字符串匹配即可。
2、那么我们应该如何找这个i呢?
①首先我们想到的最简单的方法就是两层for暴力枚举,第一层for确定i,第二层for从第一个字符串开始扫到第i-1个字符串,然后和第i个字符串相匹配,如果没有匹配上,那么就说明i是一个可行解,维护这个最大i即可。
②其上述的时间复杂度为O(n^2*len【len表示字符串长度】),明显是会超时的,那么我们如何进行优化呢?
③想到这样一个问题,如果当前i枚举到了2,而且第一个字符串已经敲定是第二个字符串的子串了,那么当i枚举到3的时候,其实就不用判断第一个字符串是否是第三个字符串的子串的问题了,这个时候我们只需要判断第二个字符串是不是第三个字符串的子串就可以了,因为如果第二个字符串是第三个字符串的子串,那么第一个字符串一定是第三个字符串的子串,如果第二个字符串不是第三个字符串的子串,那么无论第一个字符串是不是第三个字符串的子串,已经无关紧要了,因为这个时候i==3已经是一个可行解了。
3、那么按照上述思路进行算法(0<=i<n):
①初始化l=0,一层for枚举i(i从1开始);
②如果l>=i,跳③,如果l<i,那么判断第l个字符串是不是第i个字符串的子串,如果是,l++,并且继续操作②,否则记录当前i作为答案,并跳③。
③i++;
一直这样操作下去,时间复杂度接近O(n*len);做到了很大的优化。
Ac代码:
#include<string.h>
#include<stdio.h>
using namespace std;
char aa[600][5000];
char a[200005];
char b[2005];
int next[2005];
int lena;
int lenb;
void set_naxt()//子串的next数组
{
int i=0,j=-1;
next[0]=-1;
while(i<lenb)
{
if(j==-1||b[i]==b[j])
{
i++; j++;
next[i]=j;
}
else
j=next[j];
}
}
int kmp()
{
int i=0,j=0;
set_naxt();
while(i<lena)
{
if(j==-1||a[i]==b[j])
{
i++;j++;
}
else
j=next[j];
if(j==lenb)
return 1;
}
return 0;
}
int main()
{
int t;
int kase=0;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",aa[i]);
}
int l=0;
int ans=-1;
printf("Case #%d: ",++kase);
for(int i=1;i<n;i++)
{
while(l<i)
{
strcpy(a,aa[i]);
strcpy(b,aa[l]);
lena=strlen(a);
lenb=strlen(b);
if(kmp()==1)
{
l++;
}
else
{
ans=i+1;
break;
}
}
}
printf("%d\n",ans);
}
}