单词背诵【CodeVS3013】 哈希

问题描述

灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词。

文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个)。并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了。

输入格式

第1行一个数n,接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词。

接着是一个数m,然后是m行长度不超过10的字符串,每个表示文章中的一个单词。

输出格式

输出文件共2行。第1行为文章中最多包含的要背的单词数,第2行表示在文章中包含最多要背单词的最短的连续段的长度。

输入样例

3
hot
dog
milk
5
hot
dog
dog
milk
hot

输出样例

3
3

HINT

对于30%的数据 n<=50,m<=500;

对于60%的数据 n<=300,m<=5000;

对于100%的数据 n<=1000,m<=100000;

时间限制:1s

空间限制:128MB

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
using namespace std;
typedef unsigned long long uLL;
map<uLL,int>vis,Map;
map<int,uLL>b;
char a[12];
int gethash(string s)
{
    int len=s.length();
    uLL sum(0);
    for(int i=0;i<len;i++)
        sum=sum*131+s[i]-'a';
    return sum;
}
int main()
{
//    freopen("p386.in","r",stdin);
//    freopen("p386.out","w",stdout);
    int n,m,sum=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",a);
        Map[gethash(a)]=1;
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",a);
        b[i]=gethash(a);
        if(  Map[b[i]] && !vis[b[i]] )
        {
            sum++;
            vis[b[i]]=1;
        }
    }
    printf("%d\n",sum);
    vis.clear();
    int l=0,r=1,ans(1<<30),sumx=0;
    while(r<=m)
    {
        while(r<=m)
        {
            if(!vis[b[r]] && Map[b[r]] ) sumx++;
            vis[b[r]]++;
            r++;
            if(sumx==sum) break;
        }
        while(l<r && ( !Map[b[l]] || vis[b[l]]>1 ))
        {
            vis[  b[l] ]--;
            l++;
        }
        ans = min(ans,r-l);
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hfang/p/11240072.html
今日推荐