塔子哥的编程乐趣-腾讯2023笔试(codefun2000)

题目链接
塔子哥的编程乐趣-腾讯2023笔试(codefun2000)

题目内容

塔子哥是一位资深的程序员,他最近在研究一种特殊的数组操作。他有一个由正整数组成的数组,数组的长度是偶数。塔子哥可以对数组中的任意一个数字执行以下两种操作之一:将该数字乘以 2;将该数字除以 2 并向下取整。
塔子哥的目标是通过一系列操作,使得最终数组中恰好一半的数字是奇数,另一半是偶数。他希望找到一种方案,使得操作次数最少。

输入描述

输入的第一行包含一个正偶整数 n,表示数组的长度。
第二行包含 n 个正整数 A1 ,A2 ,…,An,表示初始的数组。

输出描述

输出一个整数,表示达成目标所需的最少操作次数。

样例1

输入

6
1 1 4 5 1 4

输出

1

样例2

输入

8
1 2 4 5 6 10 8 8

输出

2

提示

初始数组为 [1,1,4,5,1,4]。将第四个数字 5 除以 2 并向下取整,得到 [1,1,4,2,1,4],此时数组中恰好一半是奇数,另一半是偶数。
评测数据与规模对于所有评测用例,满足 2 ≤ n ≤ 1 0 5 , 1 ≤ A i ≤ 1 0 9 2≤n≤10^5 ,1≤Ai ≤10^9 2n105,1Ai109 ,并且 n 是偶数。

题解1

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

const int N = 1e5 + 10;
int n, cnt0, cnt1, st[N]; // st[i]表示将第i个偶数转成奇数的最少操作次数 
int main(){
	scanf("%d", &n);
	for(int i = 1, x; i <= n; i++){
		scanf("%d", &x);
		if(x&1) cnt1++; // 奇数个数+1
		else{
			 cnt0++; // 偶数个数+1 
			 for(int j = 31; j>=1; j--){
			 	// (x)&(-x)得到的是一个数的二进制表示的末尾1的对应值
				 // 比如:x=6,则的x的二进制表示为110,则(x)&(-x)=(110)&(010)= 010
				 // -6的二进制表示是对110先按位取反得到001,再加1得到010,即110 -> 001 -> 010 
			 	if(1<<j == (x&(-x))){
			 		st[cnt0] = j;
			 		break;
			 	}
			 }
		}
	}
	
	long long ans = 0;
	if(cnt0 == cnt1){ // 奇数个数和偶数个数一样多 
		ans = 0;		
	} else if(cnt0 < cnt1){ // 奇数个数多于偶数个数,只需要进行这样的操作:一个奇数乘以2,就可以得到偶数;重复这样的操作,直到奇数个数和偶数个数一样多 
		ans = (cnt1 - cnt0)/2;
	}else { // 奇数个数少于偶数个数,需要将若干偶数转成奇数;需要得到每个偶数转成奇数的最少操作数,然后按最少操作数进行升序排序,选择最小的若干个,直到奇数个数和偶数个数一样多 
		sort(st+1, st+1+cnt0);
		int num = (cnt0 - cnt1)/2; // num表示需要将偶数转变成奇数的个数 
		for(int i = 1; i <= num; i++){
			ans += st[i];
		}
	}
	printf("%lld\n", ans);
	return 0;
}
  • 19
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值