L1-7 撒狗粮
分数 20
作者 陈越
单位 浙江大学

网络上称一对情侣秀恩爱为“撒狗粮”,因为单身人士统称为“单身狗”。
在一个大型聚会上,所有宾客被安排坐在一张长条宴会桌边。如果一对情侣坐在一起,那么他们两人身边的单身狗就会被撒一脸狗粮;如果他们没有坐在一起,那么所有被夹在他们两人之间的单身狗都会被撒一脸狗粮。
本题就请你找出被撒狗粮最多(以“脸”为单位)的那位单身人士。
输入格式:
输入第一行给出一个正整数 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; }
1172

被折叠的 条评论
为什么被折叠?



