算法竞赛例题讲解:[蓝桥杯 2023 国 B] 班级活动

[蓝桥杯 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 n103
  • 对于 100 % 100\% 100% 的数据,保证 n ≤ 1 0 5 n \le 10^5 n105

第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 C 题

思路

模拟人脑来思考这个问题,当我们看到一串数字时,会先去配对已经配对好的数据,也就是将已经成对的数据匹配出来,然后对于剩下的数据,有两种情况:

  • 情况1:该数据为多出来的,例如 1 1 1 1,前面两个1配队,后面两个1就是多出来的
  • 情况2:该数据为缺少配队的:例如1 2 3 4,这四个数据都是缺少配队的。

那么我们对于剩下的这些数据,会先尝试将多出来的数据与缺少配队的进行修改配队,这样能保证修改次数最小,这个时候修改的次数为两者差的绝对值,之后,又出现两种情况:

  • 情况1:剩余的是多出的数据
  • 情况2:剩余的是缺少的数据

对于这两种情况的数据,我们分别处理:

  • 多出的数据:例如1 1,这两个数据都需要去修改,因此产生的修改次数为 多出的数据个数
  • 缺少的数据:例如1 2,这两个数据只需要修改一个就可以,因此修改的次数为 缺少的数据个数/2

关于数据处理问题,我们用桶去记录个数,用 lessnum 记录缺少的数据,用 morenum 记录多出的数据,每读取一个值后,下标为 i 的数据个数有以下三种情况:

  • 等于2
  • 小于2
  • 大于2

分别有如下三种方式对应处理:

  • 等于2:说明有一个缺少的数据被配齐了, lessnum-=1
  • 小于2:说明出现了一个缺少的数据, lessnum+=1
  • 大于2:说明出现了一个多出的数据, morenum+=1

思路清晰了就可以写代码了:

// Problem: P9421 [蓝桥杯 2023 国 B] 班级活动
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P9421
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

/*************************************************************************
	> Author: Royi 
	> Mail: royi990001@gmail.com 
	> From: 
	> Language: C/C++
 ************************************************************************/

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAX_N = 1e5 + 100;

int a[MAX_N];
int lessnum = 0, morenum = 0;

void solve() {
	int n, l = 1, r = 1;
	cin >> n;
	for (int i = 1, temp; i <= n; i++) {
		cin >> temp;
		a[temp]++;
		if (a[temp] == 2) {
			--lessnum;
			continue;
		}
		if (a[temp] < 2) {
			++lessnum;
		} else {
			++morenum;
		}
		//cout << "i = " << i << " morenum = " << morenum << " lessnum = " << lessnum << '\n';
	}
	
	int ans = 0;
	if (morenum == lessnum) {
		ans = (morenum + lessnum) >> 1;
	} else if (morenum == 0 || lessnum == 0) {
		if (morenum == 0) {
			ans = lessnum / 2;
		} else {
			ans = morenum;
		}
	} else {
		if (morenum > lessnum) {
			ans += lessnum;
			morenum -= lessnum;
			ans += morenum;
		} else {
			ans += morenum;
			lessnum -= morenum;
			ans += (lessnum >> 1);
		}
	}
	cout << ans << '\n';
	return ;
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	solve();
	return 0;
}
  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若亦_Royi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值