【洛谷P3879】阅读理解[JLOI2011]

今天介绍一种新的数据结构:Hash

以及可爱的新STL:set
首先 我们来介绍一下set
什么是set?有点像平衡树
那么什么又是平衡树呢?就是我之前讲过的二叉查找树的优化版本
嗯 我们可以把set理解成一个含有迭代器的类似数组/vector的结构
当然 它有几个特点:
1.内部自动排序 跟map有点像
2.自动去重
然后我们介绍一下set的操作:
1.s.begin() 返回s的起始迭代器
2.s.end() 返回s的末尾迭代器(注意末尾迭代器不能等于)
3.s.empty() 检查s是否为空
4.s.size() 返回s的元素数量
5.s.insert(x) 向s中插入元素x
6.s.erase(x) 在s中删除元素x
7.s.clear() 将s清空
8.swap(s1,s2) 交换s1和s2两个容器里的元素
9.s.find(x) 在s中找到x元素的迭代器
10.s.lower_bound(x) 第一个大于等于x元素的迭代器
想要迭代器可以用上期讲过的auto变量类型
值得一提的是 s的插入和查找时间复杂度为O(logn) 而删除的时间复杂度为O(1)

P3879 [TJOI2010] 阅读理解

题目描述

英语老师留了 \(N\) 篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。

输入格式

第一行为整数 \(N\) ,表示短文篇数,其中每篇短文只含空格和小写字母。

按下来的 \(N\) 行,每行描述一篇短文。每行的开头是一个整数 \(L\) ,表示这篇短文由 \(L\) 个单词组成。接下来是 \(L\) 个单词,单词之间用一个空格分隔。

然后为一个整数 \(M\) ,表示要做几次询问。后面有 \(M\) 行,每行表示一个要统计的生词。

输出格式

对于每个生词输出一行,统计其在哪几篇短文中出现过,并按从小到大输出短文的序号,序号不应有重复,序号之间用一个空格隔开(注意第一个序号的前面和最后一个序号的后面不应有空格)。如果该单词一直没出现过,则输出一个空行。

输入输出样例 #1

输入 #1

3
9 you are a good boy ha ha o yeah
13 o my god you like bleach naruto one piece and so do i
11 but i do not think you will get all the points
5
you
i
o
all
naruto

输出 #1

1 2 3
2 3
1 2
3
2

说明/提示

对于 \(30\%\) 的数据, \(1\le M\le 10^3\)

对于 \(100\%\) 的数据,\(1\le M\le 10^4\)\(1\le N\le 10^3\)

每篇短文长度(含相邻单词之间的空格)\(\le 5\times 10^3\) 字符,每个单词长度 \(\le 20\) 字符。

每个测试点时限 \(2\) 秒。

感谢@钟梓俊添加的一组数据。

解法&&个人感想

嗯嗯 我们介绍一下字符串哈希
它的思想是什么呢?为了匹配字符串 我们取一个稍大的质数p 通常是131 或者13331什么的
然后把字符串每个字符的ascil码视作一个数值 把整个字符串视为一个p进制数
然后防止溢出再模一个质数p 这样得出每个字符串的哈希值
我们采用双哈希 这样冲突的概率就不高
下面看代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m;
set<int>a[1005],b[1005];
int l[1005];
const int p1=10000019;
const int p2=10000079;
const int base=233;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&l[i]);
        char c[1005];
        for(int j=1;j<=l[i];j++){
            scanf("%s",c);
            int len=strlen(c);        
            ll tot_1=0,tot_2=0;
            for(int k=0;k<=len-1;k++){
                tot_1=(tot_1*base+c[k])%p1;
                tot_2=(tot_2*base+c[k])%p2;
            }
            a[i].insert(tot_1);
            b[i].insert(tot_2);
        }
    }  
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        char c[1005];
        scanf("%s",c);
        ll tot_1=0,tot_2=0;
        int len=strlen(c);
        for(int j=0;j<=len-1;j++){
            tot_1=(tot_1*base+c[j])%p1;
            tot_2=(tot_2*base+c[j])%p2;
        }
        for(int j=1;j<=n;j++){
            if(a[j].count(tot_1)&&b[j].count(tot_2)){
                cout<<j<<' ';
            }
        }
        cout<<endl;
    }
    system("pause");
    return 0;
}
posted @ 2025-02-16 21:23  elainafan  阅读(31)  评论(0)    收藏  举报