1206 字
5 分钟阅读
鱼与熊掌

题目描述

《孟子 · 告子上》有名言:“鱼,我所欲也,熊掌,亦我所欲也;二者不可得兼,舍鱼而取熊掌者也。”但这世界上还是有一些人可以做到鱼与熊掌兼得的。
给定 n 个人对 m 种物品的拥有关系。对其中任意一对物品种类(例如“鱼与熊掌”),请你统计有多少人能够兼得?

输入格式

输入首先在第一行给出 2 个正整数,分别是: n (\le 10 ^ 3) 为总人数(所有人从 1 n 编号)、 m (2\le m \le 10 ^ 9) 为物品种类的总数(所有物品种类从 1 m 编号)。
随后 n 行,第 i (1\le i \le n) 给出编号为 i 的人所拥有的物品种类清单,格式为:

K M[1] M[2] ... M[K]

其中 K (\le 10 ^ 3) 是该人拥有的物品种类数量,后面的 M[*] 是物品种类的编号。题目保证每个人的物品种类清单中都没有重复给出的种类。
最后是查询信息:首先在一行中给出查询总量 Q (\le 10 ^ 3) ,随后 Q 行,每行给出一对物品种类编号,其间以空格分隔。题目保证物品种类编号都是合法存在的。

输出格式

对每一次查询,在一行中输出两种物品兼得的人数。

输入样例

4 8
3 4 1 8
4 7 1 8 4
5 6 5 1 2 3
4 3 2 4 8
3
2 3
7 6
8 4

输出样例

2
0
3

题意

给出 n 个序列,查询 Q 次,问有多少个序列同时含有询问的两个不同数字。

思路

将每个序列的内容存进 unordered_set,每次询问的时候遍历所有序列,用 find 函数查找是否同时包含即可。

时间复杂度 O(nQ)

代码

void solve(){
    int n,m;
    cin >> n >> m;
    vector<unordered_set<int>> a (n);
    for(int i = 0;i < n;i++){
        int k;
        cin >> k;
        for(int j = 0;j < k;j++){
            int x;
            cin >> x;
            a[i].insert(x);
        }
    }
    int q;
    cin >> q;
    while(q--){
        int u,v;
        cin >> u >> v;
        int ans = 0;
        for(int i = 0;i < n;i++){
            if(a[i].find(u) != a[i].end() && a[i].find(v) != a[i].end()){
                ans++;
            }
        }
        cout << ans << "\n";
    }
}

1 条评论

  1. 2026年贵工程寒假训练题解 – 追求的个人博客 2026年1月18日

    […] 鱼与熊掌 题解 […]

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注