单词检索

单词检索(search)

\(Description\)

小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。
由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务。
现在他向你求助,需要你编写程序完成这项艰巨的任务。

\(Input\)

第1行3个正整数N,M,L,表示文章的数目,单词至少出现在M篇文章中和每个单词的长度。
接下来N行,每行一个字符串,表示一篇文章。

\(Output\)

仅一行,表示满足检索条件的单词数。

\(Sample Input\)

3 2 2
noip
istudycpp
imacppstudent

\(Sample Output\)

5
【样例解释】
这5个单词分别为:st,tu,ud,pp,cp。

\(Data Constraint\)

对于20%的数据有1≤N,M≤10;
对于60%的数据有1≤N,M≤100;
对于100%的数据有1≤N,M≤2000,L≤1000。每篇文章长度不大于1000,均有小写字母组成。

思路

字符串?
既然限定了答案字符的长度,那很容易想到分离字符串,统计出现个数
那就是 \(O(nl)\) 级别的个数,空间可以承受
然后怎么存分离出的字符
如果可以
对于每一篇文章,我们把分离的字符去重(因为答案要求的字符至少在N篇文章中的M篇文章里出现过)
最后合在一起
此时统计出现次数超过 \(M\) 的字符数量就是答案
想想,没有问题
关键是分离
如果把每个字符截取下来,那么一片文章处理的复杂度就是 \(O(|S|l)\)
\(n\) 篇就是 \(O(n|S|l)\) 的,显然不可以承受
然后呢?

正解

既然有了思路,那就直接打吧(也有 \(60\) 分了)
可是,现在是追求正解的时候
思路中的瓶颈在于分离字符
而我们知道要获取一段区间的信息,如果满足可加性,那就可以前缀和维护
字符串?
哦,哈希!

具体方式

对于一个字符串,我们对其进行哈希时,考虑映射成一个数字
一个很巧妙的方法是:把字符本身当做一串数字,一个字符对应权值
从高到低每一位的位权就参考十进制的方法,记作 \(B^{k-1}\)
其中 \(k\) 为第 \(k\) 位,\(B\) 是几进制
因为题中字符串均由小写字母构成
所以设为 \(26\) 进制(不这样也行,哈希映射的方法自己选择)
那么对于一个字符串S,有:

\[ H(S) = \sum_{i=1}^{|S|} c_iB^{|S|-i} \]

截取 S 中后 \(l\) 个字符组成的字符串设为 C‘,前 \(|S| - l\) 个字符组成的字符串设为 C

\[ H(C') = H(S) - H(C) * B^l \]

于是维护 \(s_i =\sum_{k=1}^i H(|1...k|)\)

双模数,以防万一

代码

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL p1 = 1e9 + 7 , p2 = 1e9 + 9 , B = 26;
LL s1[1005] , s2[1005] , b1[1005] , b2[1005];
struct node{
    LL x , y;
}d[2000005] , c[2000005];
int cnt , tot , n , m , l , ans;
char ch;

inline bool cmp(node a , node b){return (a.x < b.x || (a.x == b.x && a.y < b.y));}

int main()
{
//  freopen("单词检索.in" , "r" , stdin);
    scanf("%d%d%d" , &n , &m , &l);
    b1[0] = b2[0] = 1;
    for(register int i = 1; i <= 1001; i++) b1[i] = b1[i - 1] * B % p1;
    for(register int i = 1; i <= 1001; i++) b2[i] = b2[i - 1] * B % p2;
    int x;
    for(register int i = 1; i <= n; i++)
    {
        x = 0 , s1[0] = 0 , s2[0] = 0 , cnt = 0;
        ch = getchar();
        while (ch < 'a' || ch > 'z') ch = getchar();
        for(; ch >= 'a' && ch <= 'z'; ch = getchar())
        {
            x++;
            s1[x] = (s1[x - 1] * B % p1 + (ch - 'a' + 1)) % p1;
            s2[x] = (s2[x - 1] * B % p2 + (ch - 'a' + 1)) % p2;
            if (x >= l)
            {
                d[++cnt].x = (s1[x] + p1 - s1[x - l] * b1[l] % p1) % p1;
                d[cnt].y = (s2[x] + p2 - s2[x - l] * b2[l] % p2) % p2;
            }
        }
        sort(d + 1 , d + cnt + 1 , cmp);
        c[++tot] = d[1];
        for(register int j = 2; j <= cnt; j++)
        if (d[j].x != d[j - 1].x || d[j].y != d[j - 1].y)
            c[++tot] = d[j];
    }
    sort(c + 1 , c + tot + 1 , cmp);
    x = 1;
    while (x <= tot)
    {
        int s = 1;
        while (c[x].x == c[x + 1].x && c[x].y == c[x + 1].y && x < tot) x++ , s++;
        if (s >= m) ans++;
        x++;
    }
    printf("%d" , ans);
}

原文地址:https://www.cnblogs.com/leiyuanze/p/12368625.html

时间: 2024-10-14 04:30:46

单词检索的相关文章

对计算器和单词检索程序进行单元测试

一.编程思路 1.图逻辑框图 2.确定测试用例 3.进行单元.覆盖率测试 二.代码实现 1.计算器单元测试 首先对照代码画了类似下图的简单逻辑框图 然后对照每一个判断节点,设计了一些测试用例,在调试过程中会发现代码的一些缺陷,然后增加或者修改测试用例,下图是测试过程中的报错例子截图: 下面贴出最后完成的测试代码: 1 '''test 计算器.py''' 2 import unittest 3 4 from 计算器 import * 5 6 import HTMLTestRunner 7 8 cl

preg_match()——php

第一,让我们看看两个特别的字符:‘^’和‘$’他们是分别用来匹配字符串的开始和结束,以下分别举例说明: "^The": 匹配以 "The"开头的字符串; "of despair$": 匹配以 "of despair" 结尾的字符串; "^abc$": 匹配以abc开头和以abc结尾的字符串,实际上是只有abc与之匹配: "notice": 匹配包含notice的字符串: 你可以看见如果你

软件工程第三周作业:微软必应词典案例分析

0x01 :微软必应词典案例分析 0x0104 :微软必应词典功能性BUG说明       0x010404 : BUG – 1 – 模块功能未实现 运行环境或平台 iOS 9.0.1 必应词典软件版本 版本3.5,版权所有@2014 Microsoft 软件测试BUG特征 [优先级1]应用程序模块功能未实现,包含整个模块不能正常运行 重现步骤 1. 打开必应词典软件进入设置中,选择跨软件查词设置,设置为打开和一直运行 2. 按照使用说明所说随意打开某一App(这里选择提醒事项) 3. 按使用说

数据库课程设计

数 据库课程设计是在学生系统的学习了数据库原理课程后,依照关系型数据库的基本原理,综合运用所学的知识,以小组为单位,设计开发一个小型的管理信息系统 (MIS).通过对一个实际问题的分析.设计与实现,将原理与应用相结合,使学生学会怎样把书本上学到的知识用于解决实际问题,培养学生的动手能力:还有一 方面,使学生能深入理解和灵活掌握教学内容. 整体设计要求: 四到五人为一个小组,小组成员既要有相互合作的精神,又要分工明白.每一个学生都必须充分了解整个设计的全过程. 通讯录 1.功能需求: 1)网络版,

全文检索技术与Lucene的使用

概念 在谈全文检索之前,首先让我们来了解一下什么是信息检索.信息检索就是从信息集合中找出与用户需求相关的信息.被检索的信息除了文本外,还有图像.音频.视频等多媒体信息,这里我们只讨论文本信息的检索. 全文检索是信息检索技术的一种,主要是把用户的查询请求和全文中的每一个词进行比较,不考虑查询请求与文本语义上的匹配.在信息检索工具中,全文检索是最具通用性和实用性的. 流程 建立索引 搜索的目的是为了在大量的信息中发现自己感兴趣的信息.但是,当有了足够的资料(比如网页.Word文档.Pdf文档,或数据

Linux正则表达式grep,egrep 及相应的正则表达式用法详解

一.正则表达式介绍: 所谓正则,又称正则表达式.正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串.在很多文本编辑器里,正则表达式通常被用来检索.替换那些符合某个模式的文本. 给定一个正则表达式和另一个字符串,我们可以达到如下的目的: 1. 给定的字符串是否符合正则表达式的过滤逻辑(称作"匹配"): 2. 可以通过正则表达式,从字符

Trie(字典树)解析及其在编程竞赛中的典型应用举例

摘要: 本文主要讲解了Trie的基本思想和原理,实现了几种常见的Trie构造方法,着重讲解Trie在编程竞赛中的一些典型应用. 什么是Trie? 如何构建一个Trie? Trie在编程竞赛中的典型应用有些? 例题解析 什么是Trie? 术语取自retrieval中(检索,收回,挽回)的trie,读作"try",也叫做前缀树或者字典树,是一种有序的树形数据结构.我们常用字典树来保存字符串集合(但不仅限于字符串),如下图就是一个字典树. 它保存的字符集合是{to,te,tea,ted,te

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

概率检索模型回顾

布尔模型和向量空间模型可以给出文档内容和查询是否相关的非确定性的推测,而概率论的方法可以给这种推测提供一个基本的理论. 概率论基础知识 事件A发生的概率为P(A),它满足0≤P(A)≤1,对于两个事件A.B,它们的联合事件发生的可能性通过联合概率P(A,B)描述,条件概率P(A|B)表示在事件B发生的条件下A发生的概率.联合概率和条件概率的关系可以通过链式法则(Chain Rule)来体现: P(AB)=P(A∩B)=P(A|B)P(B)=P(B|A)P(A) 事件A 的补集的概率记为P(\ba