[codeVS1204] 单词背诵

题目描述

灵梦有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 }

 

posted @ 2017-12-18 09:23  J_william  阅读(619)  评论(0编辑  收藏  举报