【算法竞赛进阶指南】- Cinema - Codeforces 670C

题目描述:


莫斯科正在举办一个大型国际会议,有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≤n,m≤200000,
1≤ai,bi,ci≤1e9


输入样例:

3
2 3 2
2
3 2
2 3


输出样例:

2
难度:简单
时/空限制:1s / 64MB
来源:《算法竞赛进阶指南》

 

 

分析:


如果不看语言编号的数据范围,本题最简单的方法是将语言编号作为下标索引,直接统计人数。但本题的语言编号的范围是1到1e9,显然需要这种办法需要过大的内存,即使语言种类实际数量要少得多。
另一种方法则是将编号按读入的顺序存入数组 temp,排序并去重,在数组 temp 的下标 i与数值 temp[i] 之间建立映射关系,这就是《算法竞赛进阶指南》中所说的离散化(即把整数集合Z的m个整数与1~m建立映射关系,使得一个时间,空间复杂度与数值范围Z的大小有关的算法降低为时间空间复杂度与m相关)。
于是我们可以建立一个数组num,用于统计每个语言对应科学家的数量,方法是通过遍历数组a,通过find函数找到 a[i] 在temp数组中的下标i,num[ find(a[i])]++,举个例子,假如语言编号5在temp数组的下标为2,那么语言编号5在num数组的下标也为2,于是每当我们遍历到的a[i]为5时,num[[2]]就加1。我们可以利用二分查找或者lower_bound函数查找下标。
但是需要注意的是b数组和c数组会出现a数组中没出现的语言编号,会使查找出现麻烦,所以我们把所有a,b,c数组的语言编号都放进temp数组进行排序去重。数组空间也要开三倍。

 代码:

#include <iostream>
#include <algorithm>
using namespace std;
struct node{
    int b;
    int c;
    int id;
}t[200005];
int a[200005];
int temp[600010];
int num[600005];
int k;
int find (int x){
    int l = 0;
    int r = k;
    while(l < r){
        int m = (l + r) >> 1;
        if (x < temp[m])r = m;
        else l = m + 1;
    }
    if (temp[l] == x)return l;
    return l + 1;
}
bool cmp(node a, node b){
    if (a.b != b.b)return a.b > b.b;
    return a.c > b.c;
}
int main()
{
    int n;
    cin >> n;
    int tot = 0;
    for (int i = 0; i < n; i ++){
        cin >> a[i];
        temp[tot ++] = a[i];
    }
    int m;
    cin >> m;
    
    for (int i = 0; i < m; i ++ ){
        cin >> t[i].b;
        temp[tot ++] = t[i].b;
    }
    for (int i = 0; i < m; i ++){
        cin >> t[i].c;
        temp[tot ++] = t[i].c;
    }
    sort(temp, temp + tot);
    k = unique(temp, temp + tot) - temp;
    for (int i = 0; i < n; i ++)num[find(a[i])] ++;
    for (int i = 0; i < m; i ++){
        t[i].b = num[find(t[i].b)];
        t[i].c = num[find(t[i].c)];
        t[i].id = i;
    }
    
    sort(t, t + m, cmp);
    cout << t[0].id + 1 << endl;
    return 0;
}

这里find函数还可使用lower_bound函数

int find (int x){
    return lower_bound(temp, temp + k, x) - temp;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值