题目描述:
英语老师留了 N 篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。
输入格式
第一行为整数 N ,表示短文篇数,其中每篇短文只含空格和小写字母。
按下来的 N 行,每行描述一篇短文。每行的开头是一个整数 L ,表示这篇短文由 L 个单词组成。接下来是 L 个单词,单词之间用一个空格分隔。
然后为一个整数 M ,表示要做几次询问。后面有 M 行,每行表示一个要统计的生词。
输出格式
对于每个生词输出一行,统计其在哪几篇短文中出现过,并按从小到大输出短文的序号,序号不应有重复,序号之间用一个空格隔开(注意第一个序号的前面和最后一个序号的后面不应有空格)。如果该单词一直没出现过,则输出一个空行。
输入输出样例
输入 #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 ≤ M ≤ 10^3。
对于 100%100%100% 的数据,1 ≤ M ≤ 10^4
1 ≤ N ≤ 10^3 。
每篇短文长度(含相邻单词之间的空格)≤ 5×10^3字符,每个单词长度 ≤ 20 字符。
每个测试点时限 2 秒。
---------------------------分割线-------------------------------
第一反应是用桶排,如果能把单词表示成一个编码,直接用int数组就可以做了,但是显然,20个字母组成的单词编码的数据会很大。
但我可以想到可以退而求其次:对字母的前两个字母进行编码,编码相同的单词存储到同一个map< string , list>中,string记录单词,list记录单词在哪几个文章中出现。这样的由于前两个字母都一样的单词很少,查找几乎是线性时间就能结束。
建立一个这样的数组存储所有的单词。
map<string,list >article[27][27];
编码使用如下规则
编
码
=
字
符
A
S
C
I
I
码
−
′
a
′
+
1
编码 = 字符ASCII码 - 'a' + 1
编码=字符ASCII码−′a′+1
如何存储呢?假如是单词是“abc”,‘a’ - ‘a’ + 1 = 1;‘b’ - ‘a’ + 1 = 2把它存在article[1][2]里。
特别的,仅有一个字母的单词,比如"a" 存储在article[1][0]中。
查找单词时按照同样的规则。
AC代码:
#include<iostream>
#include<string>
#include<map>
#include<list>
using namespace std;
map<string,list<int> >article[27][27];
string key;//待查询的单词
void Read(int n);//输入第n篇文章
void Solve();
int main()
{
int n, m;
cin >> n;
for(int i = 1; i <= n; ++i)
Read(i);
cin >> m;
for(int i = 0; i < m; ++i)
{
cin >> key;
Solve();
}
return 0;
}
void Read(int n)
{
int l;
cin >> l;
list<int>tmp;
tmp.push_back(n);
for(int i = 0; i < l; ++i)
{
string w;
cin >> w;
int c = w[0] - 'a' + 1;
int d = 0;
if(w.size() > 1)
d = w[1] - 'a' + 1;//进行编码
pair<map<string,list<int> >::iterator,bool> flag = article[c][d].insert(make_pair(w,tmp));
if(!flag.second)//如果插入失败
flag.first->second.push_back(n);
}
}
void Solve()
{
int a = key[0] - 'a' + 1;
int b = 0;
if(key.size() > 1)
b = key[1] - 'a' + 1;
map<string,list<int> >::iterator flag = article[a][b].find(key);
if(flag != article[a][b].end())
{
list<int> *itr = &(flag->second);
int tmp = itr->front();
cout << tmp ;
for(list<int>::iterator i = itr->begin(); i != itr->end(); ++i)
{
if(*i != tmp)
{
cout << " " << *i;
}//注意list可能会插入多个相同的数值,所以需要与前一个数字比较判断
tmp = *i;
}
}
cout << endl;
}