莫斯科正在举办一个大型国际会议,有 n 个来自不同国家的科学家参会。
每个科学家都只懂得一种语言。
为了方便起见,我们把世界上的所有语言用 1 到 1e9 之间的整数编号。
在会议结束后,所有的科学家决定一起去看场电影放松一下。
他们去的电影院里一共有 m 部电影正在上映,每部电影的语音和字幕都采用不同的语言。
对于观影的科学家来说,如果能听懂电影的语音,他就会很开心;如果能看懂字幕,他就会比较开心;如果全都不懂,他就会不开心。
现在科学家们决定大家看同一场电影。
请你帮忙选择一部电影,可以让观影很开心的人最多。
如果有多部电影满足条件,则在这些电影中挑选观影比较开心的人最多的那一部。
输入格式
第一行输入一个整数 n,代表科学家的数量。
第二行输入 n 个整数 a1,a2…an,其中 ai 表示第 i 个科学家懂得的语言的编号。
第三行输入一个整数 m,代表电影的数量。
第四行输入 m 个整数 b1,b2…bm,其中 bi 表示第 i 部电影的语音采用的语言的编号。
第五行输入 m 个整数 c1,c2…cm,其中 ci 表示第 i 部电影的字幕采用的语言的编号。
请注意对于同一部电影来说,bi≠ci。
同一行内数字用空格隔开。
输出格式
输出一个整数,代表最终选择的电影的编号。电影编号 1∼m。
如果答案不唯一,输出任意一个均可。
数据范围
1≤n,m≤200000,
1≤ai,bi,ci≤1e9
题目虽然很长,但是意思应该很清楚…就是说在给出的n个科学家中,每一个科学家会一种语言,那我们就是要在这么多电影中,选出其语音语言对应的科学家的数量最多。
但是存在以下三种情况:
a.假设语言ai会的科学家最多,但是有多部电影语音使用的都是ai。
b.语言ai和语言aj会的科学家同时为最大。
c.语言ai和语言aj会的科学家同时为最大,并且有多部电影的语言使用语言ai或aj。
对于情况a,假设电影bi和bj使用的语音都是ai,这时候我们就要比较电影bi和bj使用字幕的语言对应会的科学家数量。
对于情况b,与情况a类似,比较对应的电影bi,bj使用字幕的语言对应会的科学家的数量。
对于情况c,有多部电影使用语言ai,我们就要求出其中使用字幕对应会科学家数量最多的电影bi,同样求出bj,bi再与bj比较。
因而,我们代码要解决以下问题:
1.求出科学家使用最多的一种或多种语言ai(ai,aj……)
2.求出是否有电影使用语言ai,若有,是哪个电影或哪些电影?
3.若有多部电影使用语言ai,如何比较电影字幕使用的语言ci,并选择语言ci会的科学家人数最多的一部电影?
对于问题1,这个很好办,虽然该题目被归类在排序算法的目录下,但是当我们用vector容器存储科学家会的语言时,用sort
排序即可,就算题目不能使用sort
排序,我们也可以手写一个快排。这样我们就可以求出同一种语言对应的人数,再与当前最大人数比较,若会大于等于当前值,再进入步骤2,3.
首先,我们用容器a来存储科学家使用的语言:vector
,再进行排序:sort(a.begin(),a.end())
然后,我们定义maxv
来存储某个语言对应会的科学家的人数。之后我们遍历整个容器,初始时maxv=0
,用x
来记录当前的语言,while
循环直到元素不等于x时,求出该语言对应的maxv
的值。
for(int i=0;i<=a.size()-1;;){
maxv=0;//遍历新的一个值,将其数量先定义为0
int x=t;//记录当前新的值,因为t还要去遍历其他元素
while(a[i]==x){//遍历的元素等于x一直循环
max++;
i++;
}
}
这样,每一个语言对应会的科学家的人数就求出来了。
对于问题2,我们已经求出了语言ai,我们如何求出其对应的电影编号?
首先我们考虑如何存储这一份信息,我们注意到输入的格式是按照电影编号是,我们可以知道电影i使用的语言编号x。
a.若我们用vector
来存储:vector[i]=x
,那显然我们知道x的情况下,只能用查找算法去求i的值,很花费时间的。但是如果反一下:vector[x]=i
,也不可以,因为语言x可能对应很多的电影,那到这里也很容易想到,可不可以用链表来存储?但需要注意的是,由于语言的数量ai可以达到1e9,我们手写链表肯定是不行的,所以其实我们还是用容器来存储,不过自己去定义一个链表的结构体。
用vecot
还是无法实现的,因为你容器插入只可以通过mov_lang.push_back()
,因而语言x对应的一条链表不会是mov_lang[x]
。
b.若我们用set
来存储:那你就得同时存储电影的序号和语言{i,x}
,可是你在只知道语言的情况下,根本没用办法用find()
查找。
c.若我们用hash[]
哈希表来存储;看起来似乎可以,给我一个电影编号,我找到它在Hash表中的位置,然后把对应的整个链表遍历一下。但是注意,你N取200017(大于200000)的的一个质数,你数据比较小的时候没有问题,但是一旦语言的数量超过200000,那就会有不同的语言对200000取余是同一个数,这样不同的语言就在同一个Hash表的位置当中了!!!所以会造成你可以过很多组数据,但是数据量大的几组过不了,然后会一边觉得自己的算法没有错却又不知道哪里错了(嗯…就是我,代价是30块哈哈~)
d.若我们用map
来存储,这个时候就没有问题了,甚至不需要用链表,直接用一个数组:unordered_map
,这样,当输入第i个语言使用与语音语言是x时,只需要执行操作:mov_lang[x].push_back(i)
而给定我们x时,判断是否有电影与之对应:if(t!=mov_lang.end())
,遍历所有的电影:for(auto T:mov_lang[x])
对于问题3,基于问题2,我们已经得到了电影的编号T
,事实上,编号为T的电影使用的字幕的语言为:mov_sub[T-1]
,(用容器vector
存储即可)。那么我们现在要用语言来找科学家的人数,由于语言是唯一的,所以这个好办,我们定义一个unordered_map
,在存储科学家会的语言时,输入语言x,我们只需要sci[x]++
,这样sci[x]
就是语言x使用的人数了。
那下来我们实现了,给定语言,我们选好电影,也知道电影的字幕语言,它对应科学家的人数,接下来就是比较的问题。
首先我们定义Max={{电影编号,电影语言科学家对应人数},电影字幕对应科学家人数}
,这样,在问题1中我们求出了当前这个语言的人数maxv
,进行比较:if(maxv>Max.first.second)
或者if(maxv==Max.first.second)
作为依据。
由问题2,我们得到了电影编号T,这里就必须区分一下,大于和等于的区别。
a.对于if(maxv>Max.first.second)
,我们一定要选一个电影出来(如果有对应的电影的话),并且我们要在这些电影中选择电影字幕对应科学家人数最多的电影,因而我们定义tmp=0
来表示这些电影中,ci值最大的电影。
for(auto T:mov_lang[x]){
if(sub[T-1]>=tmp){
Max={{T,maxv},sub[T-1]}};
tmp=sub[T-1];
}
}
b.对于if(maxv==Max.first.second)
,我们只有它的ci的值大于当前Max.second
的值,才要进行更换,因而不用设置tmp:
for(auto T:mov_lang[x]){
if(sub[T-1]>Max.second){
Max={{T,maxv},sub[T-1]}}};
}
}
到此,基本问题都已经解决了,但是这个题目还会存在许多临界问题。
1.sub[T-1]>=tmp
不应该写成sub[T-1]>=tmp
的,假设语言ai对应的电影bi只有一个,其字幕的语言没有一个科学家会,但是我仍然要选这个电影。
2.存在一种比较极端的情况即为,电影的语音语言没有一种是和科学家的语言是一样的,例如:
1
5
2
2 2
5 5
这样,按照之前的方法,得到的答案就是0,选不出来。但事实上我们应该直接比较ci,求出ci对应的科学家数量最大的电影:
for (int i = 0;i <= m;i++) {
if (sci[mov_sub[i]] >= maxvv) {
Max.first.first = i + 1;
maxvv = sci[mov_sub[i]];
}
}
但是这样还会有问题喔:另外一种更极端的情况下,电影语音语言,字幕语言和所有科学家的语言完全不一样,那如果按照上面的代码,得到的会是电影编号+1这时候其实随便选一部,但是你要加上:
if (Max.first.first > m && maxvv == 0) {
Max.first.first = m;
}
#include
#include
#include
#include
#include
using namespace std;
const int N = 200017;
vector<int> a;//科学家的语言..
unordered_map <int, int> sci;
unordered_map <int, vector<int>> mov_lang;
vector<int> mov_sub;//电影的字幕
int n, m;//科学家的数量,电影的数量
int main() {
cin >> n;
while (n--) {
int x;
scanf("%d", &x);
a.push_back(x);
sci[x]++;//第i个语言懂的人数,由于你i不同,所以符合map
}
cin >> m;
//对于电影的语言来说,只要有这个电影就可以,这里记录是哪部电影
for (int i = 1;i <= m;i++) {
int x;
scanf("%d", &x);//第i个电影的语言是x
mov_lang[x].push_back(i);//电影的编号
}
for (int i = 1;i <= m;i++) {
int x;
scanf("%d", &x);
mov_sub.push_back(x);//第i部电影的字幕的语言是编号x
}
sort(a.begin(), a.end());
pair<pair<int, int>, int> Max = { {0,0},0 };
for (int i = 0;i <= a.size() - 1;) {
int maxv = 0;//出现最多的次数
int x = a[i];
while (a[i] == x) {
maxv++;
i++;
}
if (maxv > Max.first.second) {//这个语言更多,看有没有对应语言的电影
auto t = mov_lang.find(x);//有这种语言出现
if (t != mov_lang.end()) {
int tmp=0;
for (auto T : mov_lang[x]) {//这样,编号就是T了
if (sci[mov_sub[T - 1]] >= tmp) {
Max = { {T,maxv},sci[mov_sub[T - 1]] };
tmp=sci[mov_sub[T - 1]];
}
}
}
}
else{
if(maxv == Max.first.second){
auto t = mov_lang.find(x);//有这种语言出现
if (t != mov_lang.end()) {
for (auto T : mov_lang[x]) {//这样,编号就是T了
if (sci[mov_sub[T - 1]] > Max.second) {
Max = { {T,maxv},sci[mov_sub[T - 1]] };
}
}
}
}
}
}
if (Max.first.first == 0) {//说明没找到一个电影,这时候完全比较字幕的
int maxvv = 0;
for (int i = 0;i <= m;i++) {
if (sci[mov_sub[i]] >= maxvv) {
Max.first.first = i + 1;
maxvv = sci[mov_sub[i]];
}
if (Max.first.first > m && maxvv == 0) {
Max.first.first = m;
}
}
}
cout << Max.first.first;//这样,pos就是编号
}
其实这一题虽然放在排序的目录下,但其实排序算法只是很小的一部分,更多的是map的灵活使用?那确实让自己对set,map的用法更加熟悉了。另外,更一般的做法其实是离散化0.0.