洛谷 P1381 单词背诵

洛谷传送门

题目描述

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

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

输入格式

第1行一个数n,

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

接着是一个数m,

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

输出格式

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

输入输出样例

输入 #1复制

输出 #1复制

说明/提示

【数据范围】

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

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

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

题解:

字符串哈希加尺取法枚举区间。

我不会告诉你这俩知识点我都是现学的。

一开始的思路约等于没有思路:挨个枚举,逐字符匹配(憨批),区间枚举。后来发现恶心的要命,根本连打的勇气都没有。

于是字符串哈希上场了。我对哈希的理解就是把一个字符串变成一个数,简化字符串匹配的过程。

关于哈希,如有不会请移步本蒟蒻的总结博客:

浅谈字符串Hash

这样的话,我们把要背的字符串的哈希值存到a数组中,并打上标记。把文章字符串的哈希值存到b数组中。然后核对标记,就可以求出第一问了。

第二问是本题的难点。

如何求出一个最短的符合要求的序列长度呢?

暴力的思路是区间枚举左右端点,核对是否符合条件。但是这样做显然不行,于是我们想到用尺取法优化区间枚举。

关于尺取法,如有不太了解的请移步本蒟蒻的总结博客:

尺取法讲解

了解了尺取法的基本内涵。针对于这道题,我们利用尺取的实现过程是这样的:

因为我们已经求得了第一问的答案,那么我们需要用这个已知答案来确定这个区间是否是可行的解。具体操作方法是:建立一个\(appear[]\)数组,存每个单词(当然是他们的哈希值)出现的次数。如果这个词是第一次出现,那么显然目前区间中的单词数量应该加一。同时,如果这个词出现的次数要是大于等于1的话,那么就尝试进行舍去,看一下有没有更优的选择。

这个地方会比较难理解:我把它叫做”不能偏安一隅“,我们不能只是在\(appear[]\)大于1的时候舍去这个点,等于1的时候一样要舍,为什么呢?就是因为,假如你选择了这个单词作为区间中唯一出现的目标单词,但是它和区间中距离它最近的另一个目标单词非常远,但是区间外面还有一个单词,和距离它最近的目标单词超级近。这个时候你应该选哪一种呢?显而易见,那个更近的对答案的贡献是更优的。所以,我们要在\(appear[]\)等于1的时候也进行舍去,然后继续扫描。因为这个时候的\(ans\)已经被更新了,所以我们不愁答案错误。

然后就求得了第二问的答案。

总的来说,这道题的思路还是比较清晰的,并没有什么太大的难点。主要是尺取法部分的代码实现。以及,提醒大家,数组的大小要开的和模数一样大,否则就会有几率RE...

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1010;
const int maxm=1e5+10;
const int mod=1e6;
const int p=31;
const int INF=1e9;
int n,m,cnt,ans=INF,l,r;
int a[maxn],b[maxm],appear[mod];
char input[110];
bool need[mod],v[mod];
int hash(char s[])
{
int len=strlen(s);
ll ret=0;
for(int i=0;i<=len;i++)
{
ret*=p,ret+=s[i]-'a';
ret%=mod;
}
return ret%=mod;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",input);
a[i]=hash(input);
need[a[i]]=1;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",input);
b[i]=hash(input);
if(need[b[i]] && !v[b[i]])
cnt++,v[b[i]]=1;
}
if(!cnt)
{
puts("0");
puts("0");
return 0;
}
else
printf("%d\n",cnt);
l=1,r=1;
while(1)
{
if(cnt)
{
if(r>m)
break;
if(need[b[r]])
{
if(!appear[b[r]])
cnt--;
appear[b[r]]++;
}
r++;
}
else
{
while(!need[b[l]])
l++;
if(l>m)
break;
ans=min(ans,r-l);
if(appear[b[l]]==1)
cnt++;
if(appear[b[l]]>=1)
appear[b[l]]--,l++;
}
}
printf("%d",ans);
return 0;
}

洛谷 P1381 单词背诵的更多相关文章

  1. 洛谷 P1381 单词背诵 解题报告

    P1381 单词背诵 题目描述 灵梦有\(n\)个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由\(m\)个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只 ...

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

    https://www.luogu.org/problemnew/show/P1381 字符串匹配,用哈希总没有错的. 然后就是尺取了,题目要求首先尽可能多覆盖,那么每次尾巴往后面长. 一开始先找到第 ...

  3. 洛谷 P1101 单词方阵

    题目链接 https://www.luogu.org/problemnew/show/P1101 题目描述 给一n×n的字母方阵,内可能蕴含多个"yizhong"单词.单词在方阵中 ...

  4. 洛谷P1808 单词分类_NOI导刊2011提高(01) 字符串排序

    洛谷P1808 单词分类_NOI导刊2011提高(01) 题目描述 Oliver为了学好英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类. 两个单词可以分为一类当且 ...

  5. 洛谷 P1019 单词接龙 (DFS)

    题目传送门 当时一看到这题,蒟蒻的我还以为是DP,结果发现标签是搜索-- 这道题的难点在于思路和预处理,真正的搜索实现起来并不难.我们可以用一个贪心的思路,开一个dic数组记录每个单词的最小重复部分, ...

  6. 洛谷——P1101 单词方阵

    https://www.luogu.org/problem/show?pid=1101#sub 题目描述 给一nXn的字母方阵,内可能蕴含多个“yizhong”单词.单词在方阵中是沿着同一方向连续摆放 ...

  7. 洛谷P1101 单词方阵——S.B.S.

    题目描述 给一nXn的字母方阵,内可能蕴含多个“yizhong”单词.单词在方阵中是沿着同一方向连续摆放的.摆放可沿着8个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间[color=red ...

  8. 洛谷P1808 单词分类

    题目描述 Oliver为了学好英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类. 两个单词可以分为一类当且仅当组成这两个单词的各个字母的数量均相等. 例如“AABA ...

  9. 洛谷 P1019 单词接龙 Label:dfs

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

随机推荐

  1. 机器学习--主成分分析(PCA)算法的原理及优缺点

    一.PCA算法的原理 PCA(principle component analysis),即主成分分析法,是一个非监督的机器学习算法,是一种用于探索高维数据结构的技术,主要用于对数据的降维,通过降维可 ...

  2. NOI Linux vim配置文件

    set nu " set mu set ruler color torte set tabstop=4 set shiftwidth=4 set autoindent set cindent ...

  3. python-openCV 绘制图形

    文档链接:https://docs.opencv.org/trunk/dc/da5/tutorial_py_drawing_functions.html 文档描述了OpenCV的几个绘图功能: 绘制圆 ...

  4. 趣谈Linux操作系统学习笔记:第二十九讲

    一.引子 在这之前,有一点你需要注意.解析系统调用是了解内核架构最有力力的一把钥匙,这里我们只要重点关注这几个最重要的系统调用就可以了 1.mount 系统调用用于挂载文件系统:2.open 系统调用 ...

  5. saltstack--史上最细致安装攻略!亲测无坑

    准备一台虚拟机node1: [root@linux-node1 pillar]# ifconfig ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAS ...

  6. python画一片绿叶给你

    怎么用 turtle 画一个 π 字,于是我顺手到网上大致搜了下,发现网上没有画这个 π 字的,接着又用谷歌加英文搜索了下,还是没找到现成的答案. 不过通过这次搜索意外发现了一个有趣的网站,网站上有大 ...

  7. Leetcode练习题Search Insert Position

    Question: Given a sorted array and a target value, return the index if the target is found. If not, ...

  8. Java语言入门-第一个HelloWorld程序

    1.官网下载Jdk 这里给出官网下载网址:https://www.oracle.com/technetwork/java/javase/downloads . 1.1 打开之后出现如下界面: 1.2选 ...

  9. javaScript之基础介绍

    前言一:javascript历史背景介绍 布兰登 • 艾奇(Brendan Eich,1961年-),1995年在网景公司,发明的JavaScript. 一开始JavaScript叫做LiveScri ...

  10. centos7开启,关闭防火墙

    1.查看防火墙状态 firewall-cmd --state 2.停止防火墙 systemctl stop firewalld.service 3.禁止防火墙开机启动 systemctl disabl ...