Problem Description
我们都知道,学习英语单词最好的方法就是在相应的句子和语言环境中学习。小W最近定下来一个学习单词的计划,他要背n个单词,但他想通过背一篇文章的一段来记住这些单词。
假定现在小W手中有一篇包含m个单词的文章,他想在文章中找出连续的一段,其中包含最多的他所要背的单词(重复的只算一个),并且使这段连续的单词长度最短。这样他就可以用尽量短的时间学习尽可能多的单词了。
假定现在小W手中有一篇包含m个单词的文章,他想在文章中找出连续的一段,其中包含最多的他所要背的单词(重复的只算一个),并且使这段连续的单词长度最短。这样他就可以用尽量短的时间学习尽可能多的单词了。
Input
输入有多组数据。每组数据的第1行为一个数n(1<=n<=1000),接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词。接下来是一个数m(1<=m<=100000),然后是m行长度不超过10的字符串,每个表示文章中的一个单词。
Output
对于每组数据输出2行,第1行为文章中最多包含的要背的单词数,第2行表示在文章中包含最多要背单词的最短的连续段的长度。
Sample Input
3 hot dog milk 5 hot dog dog milk hot
Sample Output
3 3
#include<stdio.h> #include<string.h> #include<stdlib.h> int n,m; //n表示要背的单词,m表示文章包含的单词数 char word[1010][15]; //要背的单词列表 int point[1010]; //word数组的索引 int index[100010]; //记录文章中各单词对应单词表中的相应单词的下标 int mark[10010]; //表示当前的区段里各单词的出现次数 int cmp(const void *a, const void *b) //比较函数,按字典序比较 { return strcmp(word[*(int*)a],word[*(int*)b]); } int find(char *s) //在单词表中查找单词s,放回在单词表中的下标 { int first,last,mid,temp; first=0; last=n-1; while(first<=last) //采用二分查找 { mid=(first+last)/2; temp=strcmp(s,word[point[mid]]); if(temp==0) return mid; /到就返回下标 else if(temp<0) last=mid-1; else first=mid+1; } return -1; /不到返回-1 } int main() { //freopen("a.in","r",stdin); int i; char s[20]; //读入单词表 while(~scanf("%d",&n)) { for(i=0;i<n;i++) scanf("%s",word[i]); //point为word索引,然后对其进行排序,即对要背的单词进行字典排序 for(i=0;i<n;i++) point[i]=i; qsort(point,n,sizeof(point[0]),cmp); //读入文章 scanf("%d",&m); for(i=0;i<m;i++) { scanf("%s",s); index[i]=find(s); //在单词表里找与文章中这单词一样的单词,记录其下标 } memset(mark,0,sizeof(mark)); int first=0,last=0,total=0,min=0; while(last<m) { if(index[last]>=0) //如果此单词在单词表中有相同的 { if(mark[index[last]]==0) //如果此单词在文章中第一次出现 { total++; min=last-first+1; } mark[index[last]]++; } //调整first,产生以last结尾包含最多单词的最短序列 while(first<=last) if((index[first]>=0&&mark[index[first]]>1)||index[first]<0) { mark[index[first]]--; first++; } else break; //比较此序列的长度 if(last-first+1<min) min=last-first+1; last++; //last每步增1 } printf("%d\n%d\n",total,min); } return 0; }