【luogu P1381单词背诵】题解

单词背诵

题目描述

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

题目意思:

给出两个单词集。

1.问集合1中的单词,有多少个在集合2中出现。

2.求在满足第一问的最多出现次数的情况下,集合2中最短的连续子集。

分析:

由于字符处理起来不是很方便,因此我们使用哈希将字符串转化成数字,这样处理起来会比字符串方便的多。

当然也可以使用 map 来存。

对于第一问比较简单。

用一个bool 数组v1[] 0/1 记录这个单词是否在集合1中出现过(1:是,0:否);

然后对集合2进行判断。

难点在第二问。

n的规模比较大,可以想到基本是需要线性的了。

我提供一种单调队列做法。

首先申明几个变量:

1. lst [ 哈希值(s) ] 表示处理到当前字符串,字符串s上一次出现的位置在哪里。

2. num 计数器,表示处理到当前字符串,有贡献的字符串个数,即为出现在集合1里的字符串个数(相同算一次)。

3. v2[ 哈希值(s) ] 表示s是否出现在集合1和集合2中,若没有,则无需考虑这个字符串。

可以明确得到,当num=ans1时,更新一次答案。

接下来最重要的就是单调队列里面放什么?

我们放进去的是每个有贡献的字符串 b[i] 。

满足单调性的是他们的位置。

如果下一个相同的字符串出现了,就可以把它弹掉了。

这样当我们统计答案时(num==ans1)

我们用当前位置 i 减去队列首元素的位置+1,就是这一段满足条件区间长度。

最后特判一下0.

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e6,P=1e7+9,inf=1e9;
int n,m,ans1,ans2=inf;
int a[N],b[N];
bool v1[P+1],v2[P+1],vis[P+1];
int lst[P],q[N];
char s[20];
inline int hash(char *s){//哈希函数
    int len=strlen(s);
    long long res=0;
    for(int i=0;i<len;i++){
        res*=31;
        res+=s[i]-‘a‘;
        res%=P;
    }
    return res;
}
int main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%s",s);
        a[i]=hash(s);
        v1[a[i]]=1;//v1[] 记录是否在集合1中出现
    }
    scanf("%d",&m);
    for(i=1;i<=m;i++){
        scanf("%s",s);
        b[i]=hash(s);
        if(v1[b[i]]){
            if(!v2[b[i]]){
                v2[b[i]]=1;
                ans1++;
            }
        }
    }
    int num=0,head=1,tail=0;
    for(i=1;i<=m;i++){
        if(lst[b[i]]==0&&v2[b[i]]) num++;
        if(v2[b[i]]){//如果!v2[]一定不会有贡献
            lst[b[i]]=i;
            q[++tail]=i;
        }
        while(head<=tail&&q[head]<lst[b[q[head]]]) head++;
        if(num==ans1) ans2=min(ans2,i-q[head]+1);//更新答案
    }
    if(ans1) printf("%d\n%d",ans1,ans2);
    else printf("0\n0");
}

原文地址:https://www.cnblogs.com/quitter/p/11774334.html

时间: 2024-10-09 22:13:03

【luogu P1381单词背诵】题解的相关文章

[CODEVS3031] 单词背诵 - 字符串hash

3013 单词背诵 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个).并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了. 输入描述 Input Description 第1行一个数n, 接下来n行每行是一个

Luogu P1101 单词方阵

明明是一道水题,我还找不出 bug 来...原本在 DFS 途中记录单词串,只好使用笨方法,在结尾加一个 for 记录单词串.终于过了. 思路:枚举图中每一个点进行 DFS,途中判断访问的点是否为连续元素("yizhong"字符串中连续),如果不是返回:进行下一层 DFS,如果返回值 True 则直接层层返回 True,强行退出. 1 /* P1101 单词方阵 2 * Au: GG 3 */ 4 #include <cstdio> 5 #include <cstdl

基于Qt5.5.0的sql数据库、SDK_tts文本语音朗读的CET四六级单词背诵系统软件的编写V1.0

作者:小波 QQ:463431476 请关注我的博客园:http://www.cnblogs.com/xiaobo-Linux/  感觉我要火~~这比我是装定了!! 我的第二款软件:CET四六级单词背诵软件.基于QT5.5.0.sql数据库.以及TTS文本识别语音单词朗读的一款软件. 第一款软件的sql数据库软件的编写:http://www.cnblogs.com/xiaobo-Linux/p/4676950.html 现在来讲解我的第二款高大上的代码: 这个是.pro的代码,其中axconta

单词背诵 500 个考过二十次以上词汇

单词背诵 500 个考过二十次以上词汇above / beyond:  介词,后面接抽象而不是具体名词时表示 “ 无法做到 ” ,例如: “above comprehension” 的意思是 “ 无法理解 ”. .in the absence of something: “ 缺少,没有 ” ,用于替代 “in short of” 或者 “be lacking in” .be absorbed in something: “ 专心从事 ” .abuse:  用在物品词后面表示 “ 过量使用 ” ,

luogu P1541 乌龟棋 题解

\(luogu\) P1541 乌龟棋 题解 题目描述 这道题目想状态的时候想多了一维表示当前走了多少步,其实这个完全没有必要,因为根据你的牌的使用就可以知道你当前在哪一个位置. 状态 设\(f[i][j][k][l]\)表示已经用了\(i\)张步数为\(1\)的牌,\(j\)张步数为\(2\)的牌,\(k\)张步数为\(3\)的牌,\(l\)张步数为\(4\)的牌所能取得的最大分数. 转移 因为只有这四种牌,所以只需要枚举到达当前的步数的最后一步用的那张牌,然后对用四种牌的情况取\(\max\

【题解】单词背诵

QUESTION_POS 本来想用\(trie\)的,结果有一个神奇的数组赋值无效-- 思路:先求出第一问答案,可以\(O(n)\)一遍扫出来,注意背诵的单词只统计一次 难点在于第二问. 可以用单调队列扫一下,记录队列中每个单词在文章中的位置,对于队头,如果这里的单词在后面出现过,队头就可以不要了. 当队伍中单词达到数量时,可以统计答案了. #include<cstdio> #include<cstring> #include<iostream> #include<

【CodeVS3013】单词背诵

Description 灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个).并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了. Input 第1行一个数n, 接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词. 接着是一个数m, 然后是m行长度不超过10的字符串,每个表示文章中的一个单词. Output 输出文件共2

CODEVS——T 3013 单词背诵

http://codevs.cn/problem/3013/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个).并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了. 输入描述 Input

codevs 3013 单词背诵 hash

题目链接 题目描述 Description 灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个).并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了. 输入描述 Input Description 第1行一个数n, 接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词. 接着是一个数m, 然后是m行长度不超过10的字符串,