L1-7 撒狗粮

L1-7 撒狗粮

分数 20

作者 陈越

单位 浙江大学

sgl.jpg

网络上称一对情侣秀恩爱为“撒狗粮”,因为单身人士统称为“单身狗”。
在一个大型聚会上,所有宾客被安排坐在一张长条宴会桌边。如果一对情侣坐在一起,那么他们两人身边的单身狗就会被撒一脸狗粮;如果他们没有坐在一起,那么所有被夹在他们两人之间的单身狗都会被撒一脸狗粮。
本题就请你找出被撒狗粮最多(以“脸”为单位)的那位单身人士。

输入格式:

输入第一行给出一个正整数 N(≤ 50 000),是已知情侣的对数;随后 N 行,每行给出一对情侣——为方便起见,每人对应一个 ID 号,为 5 位数字(从 00000 到 99999),ID 间以空格分隔;之后给出一个正整数 M(≤ 80 000),为参加派对的总人数;随后一行按座位从左到右的顺序给出这 M 位客人的 ID,以空格分隔。题目保证无人脚踩两条船。

输出格式:

在一行中输出被撒狗粮最多的单身人士。如果不唯一,按 ID 递增顺序列出。ID 间用 1 个空格分隔,行的首尾不得有多余空格。
题目保证至少有一个输出。

输入样例:

4
11111 22222
33333 44444
55555 66666
77777 88888
10
11111 33333 88888 22222 23333 55555 66666 10000 44444 12345

输出样例:

10000 23333 88888

注意:88888 虽然有伴侣,但在聚会上是单身。

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

栈限制

8192 KB

代码

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;

// unordered_map<int, int> dogFoodNum; // 狗粮数量
typedef pair<int, int> dogFood; // 对应的狗粮数量
vector<dogFood> dogFoodNum;     // 狗粮数量

void offerDogFood(int start, int end) // 应用前缀和增加狗粮
{
    dogFoodNum[start].second += 1;
    dogFoodNum[end + 1].second -= 1;
}

bool compareDogFood(dogFood a, dogFood b)
{
    if (a.second != b.second)       // 如果狗粮数量不相同
        return a.second > b.second; // 狗粮数大的在前面
    else                            // 狗粮数量相同
        return a.first < b.first;   // 按照ID递增排序
}
int main()
{
    int N; // 情侣对数
    cin >> N;
    unordered_map<int, int> couples; // 储存所有的情侣
    for (int i = 0; i < N; i++)
    {
        int coupleA, coupleB;
        cin >> coupleA >> coupleB;  // 输入一对情侣
        couples[coupleA] = coupleB; // 情侣存入情侣库
        couples[coupleB] = coupleA;
    }
    // 初始化派对情况
    int guestsNum; // 参加派对的总人数
    cin >> guestsNum;
    vector<int> guests;
    unordered_map<int, int> guestPos; // 储存位置
    for (int i = 0; i < guestsNum; i++)
    {
        int tempGuest;
        cin >> tempGuest;
        guests.push_back(tempGuest);
        dogFoodNum.push_back(make_pair(tempGuest, 0)); // 初始化狗粮数为0
        guestPos[tempGuest] = i;
    }
    // 标记派对上的情侣
    unordered_map<int, bool> isCouple; // 储存派对上是情侣的人
    unordered_map<int, bool> hasOffer;
    for (int i = 0; i <= guests.size(); i++)
    {
        isCouple[couples[guests[i]]] = true; // 把每个参加派对的人的对象标记为true,自己则等到遍历到对象的时候再标记为true,这样就可以使得对象不在派对的不会被标记为true
        hasOffer[couples[guests[i]]] = false;
    }
    // 开始撒狗粮
    for (int i = 0; i < guests.size(); i++)
    {
        if (!isCouple[guests[i]] || hasOffer[guests[i]]) // 不是情侣或者是已经撒过狗粮的
            continue;
        if (guests[i + 1] == couples[guests[i]]) // 如果情侣坐在一起
        {
            if (i - 1 >= 0 && !isCouple[guests[i - 1]])            // 检查左边的人符合条件才加狗粮
                offerDogFood(i - 1, i - 1);                        // 给左边的人加狗粮
            if (i + 2 < guests.size() && !isCouple[guests[i + 2]]) // 检查右边的人符合条件才加狗粮
                offerDogFood(i + 2, i + 2);                        // 给右边的人加狗粮
            hasOffer[guests[i]] = true;                            // 标记为已经撒狗粮
            hasOffer[couples[guests[i]]] = true;
        }
        else if (isCouple[couples[guests[i]]]) // 如果情侣没有坐在一起
        {
            offerDogFood(i + 1, guestPos[couples[guests[i]]] - 1);
            hasOffer[guests[i]] = true;
            hasOffer[couples[guests[i]]] = true;
        }
    }
    // 应用前缀和计算狗粮
    for (int i = 0; i < guests.size(); i++)
    {
        dogFoodNum[i].second += dogFoodNum[i - 1].second;
    }
    // 有伴侣的人狗粮数量设为0
    for (int i = 0; i < dogFoodNum.size(); i++)
    {
        if (isCouple[dogFoodNum[i].first])
            dogFoodNum[i].second = 0;
    }
    sort(dogFoodNum.begin(), dogFoodNum.end(), compareDogFood);
    int maxDogFoodNum = dogFoodNum[0].second;
    for (int i = 0; i < dogFoodNum.size(); i++)
    {
        if (dogFoodNum[i].second == maxDogFoodNum)
            cout << ((i == 0) ? "" : " ") << setfill('0') << setw(5) << dogFoodNum[i].first;
    }
}
  • 使用前缀和计算的技巧,减少了计算量

    void offerDogFood(int start, int end) // 应用前缀和增加狗粮
    {
        dogFoodNum[start].second += 1;
        dogFoodNum[end + 1].second -= 1;
    }
    
        // 应用前缀和计算狗粮
        for (int i = 0; i < guests.size(); i++)
        {
            dogFoodNum[i].second += dogFoodNum[i - 1].second;
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值