Bazinga
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 6170 Accepted Submission(s): 1902
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亚洲区沈阳站-重现赛(感谢东北大学)
Recommend
wange2014
Statistic | Submit | Discuss | Note
题目大意:
给出n个字符串,找到最大的j使得从1->j-1中存在s[i]不是s[j]的子串。
思路:
如果直接枚举两个串复杂度为50*500*500=12500000,还不加匹配算法的复杂度,超时。
现在想可不可以剪枝。
两层循环,第一层i枚举所有子串,第二层j枚举母串。
如果s[i]是s[j]的子串,则s[i]串的贡献完全可以转化成s[j]串,则直接break到下一个子串.
如果s[i]串不是s[j]的子串,则s[j]串即为满足题目要求的,标记下来,以后遍历母串跳过s[j]即可。
然后遍历寻找最大的j即可。
KMP版代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 500 + 5;
char s[maxn][2500];
int t, n;
int p[maxn], nxt[maxn][2500], len[maxn];
void getNext(int t) {
int i, j;
j = nxt[t][0] = -1;
i = 0;
while(i < n) {
while(j != -1 && s[t][i] != s[t][j]) j = nxt[t][j];
nxt[t][++i] = ++j;
}
}
//判断s[v]是否包含s[u]
int kmp(int v, int u) {
int i, j;
i = j = 0;
while(i < len[v]) {
while(j != -1 && s[v][i] != s[u][j]) j = nxt[u][j];
i++;j++;
if(j >= len[u]) {
return 1;
}
}
return 0;
}
int solve() {
memset(p,1,sizeof(p));
int ans = -1;
for(int i = 1; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
if(p[j]) {
if(kmp(j, i)) break;
else {
p[j] = 0;
ans = max(ans, j);
}
}
}
}
return ans;
}
int main() {
scanf("%d", &t);
for(int kase = 0; kase < t; kase++) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%s", s[i]);
len[i] = strlen(s[i]);
getNext(i);
}
printf("Case #%d: %d\n",kase+1, solve());
}
return 0;
}
看了别人的AC,才直到有strstr函数,可以寻找s[i]在s[j]串中的位置。
strstr版代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
using namespace std;
const int maxn = 500 + 5;
char s[maxn][2500];
int t, n;
int p[maxn];
int solve() {
memset(p,1,sizeof(p));
int ans = -1;
for(int i = 1; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
if(p[j]) {
if(strstr(s[j], s[i])) break;
else {
p[j] = 0;
ans = max(ans, j);
}
}
}
}
return ans;
}
int main() {
scanf("%d", &t);
int kase = 0;
while(t--) {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%s", s[i]);
printf("Case #%d: %d\n",++kase, solve());
}
return 0;
}