[蓝桥杯 2023 国 B] 班级活动
题目描述
小明的老师准备组织一次班级活动。班上一共有 n n n 名( n n n 为偶数)同学,老师想把所有的同学进行分组,每两名同学一组。为了公平,老师给每名同学随机分配了一个 n n n 以内的正整数作为 id,第 i i i 名同学的 id 为 a i a_i ai。
老师希望通过更改若干名同学的 id 使得对于任意一名同学 i i i,有且仅有另一名同学 j j j 的 id 与其相同( a i = a j a_i = a_j ai=aj)。请问老师最少需要更改多少名同学的 id?
输入格式
输入共 2 2 2 行。
第一行为一个正整数 n n n。
第二行为 n n n 个由空格隔开的整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an。
输出格式
输出共 1 1 1 行,一个整数。
样例 #1
样例输入 #1
4
1 2 2 3
样例输出 #1
1
提示
样例说明
仅需要把 a 1 a_1 a1 改为 3 3 3 或者把 a 4 a_4 a4 改为 1 1 1 即可。
评测用例规模与约定
- 对于 20 % 20\% 20% 的数据,保证 n ≤ 1 0 3 n \le 10^3 n≤103。
- 对于 100 % 100\% 100% 的数据,保证 n ≤ 1 0 5 n \le 10^5 n≤105。
第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 C 题
思路
首先,定义了一些常量和变量。其中,N
是数组的最大长度,n
是同学的数量,a
是存储同学ID的数组,cnt
是存储每个ID的数量的数组。x
和 y
是两个计数器,表示需要匹配id的学生数量和需要改变id的学生数量。
读取学生的数量 n
和他们的ID a[i]
。它使用一个数组 cnt[]
来计算每个ID的学生数量。
然后,它遍历 cnt[]
数组。对于每个ID i
,如果有且仅有一个学生的ID为 i
,则增加 x
。这意味着这个学生需要匹配另一个学生的ID。如果有超过两个学生的ID相同,那么它将 y
增加 cnt[i] - 2
。这意味着这些学生中的一部分需要改变他们的ID以匹配其他学生的ID。
如果一个ID只分配给了一个同学(x
),那么这个同学需要找一个其他同学更改ID以形成一对。如果一个ID分配给了超过两个同学(y
),那么这些同学中的一部分需要更改ID,使得每个ID只对应两个同学。在这个过程中,优先处理y
,因为这些同学可以直接更改ID形成新的对,而不需要影响其他同学。
如果 x
(需要匹配的学生数量)大于 y
(需要改变的学生数量),那么输出 ((x - y) >> 1) + y
。先让所有需要改变的学生都更改ID。剩下的部分中,每两个学生中只需要改变其中一人的ID就能匹配,所以需要除以2。
如果 x
小于或等于 y
,那么输出 y
,因为这些学生可以直接改变他们的ID以匹配其他学生。
AC代码
cpp
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;
const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
int n;
int a[N];
int cnt[N];
// 改别人的id
int x = 0;
// 自己要改id
int y = 0;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
memset(cnt, 0, sizeof(cnt));
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
cnt[a[i]]++;
}
for (int i = 1; i <= n; i++) {
if (cnt[i] == 1) {
x++;
} else if (cnt[i] > 2) {
y += cnt[i] - 2;
}
}
if (x > y) {
cout << ((x - y) >> 1) + y << "\n";
} else {
cout << y << "\n";
}
return 0;
}