题目描述
灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词。
文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个)。并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了。
输入输出格式
输入格式:第1行一个数n,
接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词。
接着是一个数m,
然后是m行长度不超过10的字符串,每个表示文章中的一个单词。
输出格式:输出文件共2行。第1行为文章中最多包含的要背的单词数,第2行表示在文章中包含最多要背单词的最短的连续段的长度。
输入输出样例
输入样例#1:
3 hot dog milk 5 hot dog dog milk hot
输出样例#1:
3 3
说明
【数据范围】
对于30%的数据 n<=50,m<=500;
对于60%的数据 n<=300,m<=5000;
对于100%的数据 n<=1000,m<=100000;
思路
Trie离散化一下,然后先统计一下ans1,ans2通过对离散化和的数组尺取法求出。
代码实现
1 #include<cstdio> 2 #include<cstring> 3 const int maxn=1e3+10; 4 const int maxm=1e5+10; 5 inline int min_(int x,int y){return x<y?x:y;} 6 int n,m,ans,now,top,map,lng=1e9; 7 int s[maxm],v[maxn]={1}; 8 struct tree{int tn,tp;}t[maxm][30]; 9 char ch[12]; 10 void add(int k,int i){ 11 if(ch[i]==0) return; 12 int next=ch[i]-‘a‘; 13 if(!t[k][next].tn) t[k][next].tn=++top; 14 add(t[k][next].tn,i+1); 15 } 16 int search(int k,int i){ 17 int next=ch[i]-‘a‘; 18 if(ch[i]==0){ 19 if(!t[k][0].tp) t[k][0].tp=++map; 20 return t[k][0].tp; 21 } 22 if(!t[k][next].tn) return 0; 23 return search(t[k][next].tn,i+1); 24 } 25 int main(){ 26 scanf("%d",&n); 27 for(int i=1;i<=n;i++){ 28 scanf("%s",ch); 29 add(0,0); 30 } 31 scanf("%d",&m); 32 for(int i=1;i<=m;i++){ 33 scanf("%s",ch); 34 s[i]=search(0,0); 35 if(!v[s[i]]) v[s[i]]++,ans++; 36 } 37 printf("%d\n",ans); 38 memset(v,0,sizeof(v)),v[0]=1; 39 for(int i=1,j=1;i<=m;i++){ 40 while(now<ans&&j<=m){ 41 if(!v[s[j]]) now++; 42 v[s[j]]++; 43 j++; 44 } 45 if(now==ans) lng=min_(lng,j-i); 46 v[s[i]]--; 47 if(!v[s[i]]) now--; 48 } 49 printf("%d\n",lng); 50 return 0; 51 }