洛谷 - P1381 - 单词背诵 - 哈希 - 尺取

https://www.luogu.org/problemnew/show/P1381

字符串匹配,用哈希总没有错的。
然后就是尺取了,题目要求首先尽可能多覆盖,那么每次尾巴往后面长。
一开始先找到第一个要的词汇。这个不多说。
然后每次往后面长,遇到非法词汇就继续长。
遇到合法的,就把头部所有合法的重复词和非法词都取出来。
注意要特殊处理非法词。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;


typedef unsigned long long ull;


unordered_set<ull> dic;//要背的单词的词典
unordered_map<ull,int> cnt;//当前区间要背单词的数量

int n,m;
ull get_hash(char *s) {
    ull res=0;
    for(int i=0; s[i]!='\0'; i++) {
        res=res*19260817+s[i];
    }
    return res;
}

char str[15];
ull a[100005];

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%s",str);
        dic.insert(get_hash(str));
    }
    scanf("%d",&m);
    int cntv=0;
    int len=0;
    int head=1;//尺取区间的头

    int maxcnt=0;
    int maxcnt_len=0;
    for(int i=1; i<=m; i++) {
        scanf("%s",str);
        ull ha=get_hash(str);
        a[i]=ha;
        if(cnt.size()==0) {
            //刚刚开始处理,尺取区间里面没有有效单词
            if(!dic.count(ha)) {
                //这个单词也是无效的,直接把head指向下一个位置
                head++;
            } else {
                //这个单词是有效的,包含进来
                cnt[ha]++;
                //head固定在这里了,新单词导致cntv上升
                cntv++;
                //第一个单词使得len也上升了
                len++;
                if(cntv>=maxcnt) {
                    if(cntv>maxcnt) {
                        maxcnt=cntv;
                        maxcnt_len=len;
                    } else {
                        maxcnt_len=min(maxcnt_len,len);
                    }
                }
            }
        } else {
            //尺取区间的单词列表中至少有一个
            if(!dic.count(ha)) {
                //就算没用但是可能会把后面连起来,记上
                len++;
            } else {
                //这个词是有用的
                if(!cnt.count(ha)) {
                    //这个词没见过
                    cntv++;
                }
                cnt[ha]++;
                len++;
                while(!dic.count(a[head])||cnt[a[head]]>=2) {
                    //头部是非法词汇,或者头部是合法词汇,且至少重复了1次,把头部取出
                    if(dic.count(a[head]))
                        cnt[a[head]]--;
                    head++;
                    len--;
                }
                //现在头部必定是不重复的合法词汇,且至少有1个
                if(cntv>=maxcnt) {
                    if(cntv>maxcnt) {
                        maxcnt=cntv;
                        maxcnt_len=len;
                    } else {
                        maxcnt_len=min(maxcnt_len,len);
                    }
                }
            }
        }
    }

    printf("%d\n%d\n",maxcnt,maxcnt_len);

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/11013780.html
今日推荐