codevs3013单词背诵

/*
手打的哈希+线性的维护
第一问:hash一下 并且用个h记录某个单词要背的
第二问:线性的跑一边 
开始队列里装下前一些单词使这一坨符合要求 并且记录出现次数num 
然后开始从前面删
删除的条件:要么是非法的单词(h值为0)
            要么num值大于1
如果删不了就在进来一个 更新num
直到跑完  这过程中每次更新l 
注意这样有极端数据 如果第一问答案为 0 需要特判一下 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define maxm 100100
#define maxn 100010
#define mod 100007
#define p 17
using namespace std;
char s[maxn][12],ss[maxn][12];
int n,m,f[maxn],a[maxm],ans,l=maxn;
int h[maxn],num[maxn],vis[maxn],head,tail;
int get_hash(char *str)
{
    int len=strlen(str),hash=0;
    for(int i=0;i<=len-1;i++)
      hash=(hash*p+str[i]-'a')%mod;
    return hash;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      scanf("%s",s[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
      {
          scanf("%s",ss[i]);
        f[get_hash(ss[i])]=1;
      }
    for(int i=1;i<=n;i++)
      {
          int tmp=get_hash(s[i]);
          if(f[tmp]==1)
          {
            ans++;
            h[tmp]=1;
          }
      }
    int si=0;
    head++;
    while(tail<=m)
      {
          int tmp=get_hash(ss[++tail]);
          if(h[tmp])
          {
              if(vis[tmp]==0)
              si++;
              num[tmp]++;
              vis[tmp]=1;
          }
          if(si==ans&&si!=0)
            {
                int x=get_hash(ss[head]);
                while(head<tail&&(h[x]==0||num[x]>1))
                  {
                      if(h[x])
                  num[x]--;
                x=get_hash(ss[++head]);
              }
            l=min(l,tail-head+1);
          }
      }
    if(ans)printf("%d\n%d\n",ans,l);
    else printf("0\n0");
}

 

posted @ 2016-05-08 17:41  一入OI深似海  阅读(227)  评论(0编辑  收藏  举报