2020牛客寒假算法基础集训营——I.建通道【最小生成树 -> 二进制 & 思维】

在无垠的宇宙中,为了在n个星球间穿梭,需要建立传送通道。每对星球间建立通道的费用基于它们的权值和二进制异或运算。本题探讨如何以最小成本使所有星球相互可达,详细阐述了问题描述、输入输出格式、解题思路及高效解决方案。
摘要由CSDN通过智能技术生成

题目传送门


题目描述

在无垠的宇宙中,有 n 个星球,第 i 个星球有权值 v i v_i vi
由于星球之间距离极远,因此想在有限的时间内在星际间旅行,就必须要在星球间建立传送通道。
任意两个星球之间均可以建立传送通道,不过花费并不一样。第 i 个星球与第 j 个星球的之间建立传送通道的花费是 lowbit ( v i ⊕ v j ) \text{lowbit}(v_i\oplus v_j) lowbit(vivj),其中 ⊕ \oplus 为二进制异或,而 lowbit ( x ) \text{lowbit}(x) lowbit(x) 为 x 二进制最低位 1 对应的值,例如 lowbit ( 5 ) = 1 , lowbit ( 8 ) = 8 \text{lowbit}(5)=1,\text{lowbit}(8)=8 lowbit(5)=1,lowbit(8)=8。特殊地, lowbit ( 0 ) = 0 \text{lowbit}(0)=0 lowbit(0)=0
牛牛想在这 n 个星球间穿梭,于是――你需要告诉 牛牛,要使这 n 个星球相互可达,需要的花费最少是多少。


输入描述:

第一行,一个正整数 n 。
第二行,n 个非负整数 v 1 , v 2 , … , v n v_1,v_2,\dots,v_n v1,v2,,vn
保证 1 ≤ n ≤ 2 × 1 0 5 , 0 ≤ v i < 2 30 1\leq n\leq 2\times 10^5 ,0\leq v_i < 2^{30} 1n2×1050vi<230


输出描述:

输出一行,一个整数表示答案。


输入

2
1 2


输出

1


说明

1 、 2 \text{}1、2 12 号点之间建立通道, v 1 ⊕ v 2 = 3 , lowbit ( 3 ) = 1 v_1 \oplus v_2=3, \text{lowbit}(3)=1 v1v2=3,lowbit(3)=1


题解

  • 首先将权值去重(权值相等的点连接代价为 0 ),设去重后有 m 个点,接下来找到最小的二进制位 k ,满足存在 v i v_i vi 的这个二进制位是 0 且存在 v j v_j vj 的这个二进制位是 1 ,答案就是 2 k × ( m − 1 ) 2^k\times (m-1) 2k×(m1)(相当于所有这位是 0 的点与 j 点连边,是 1 的点与 i 点连边)。

  • 排序和去重以外时间复杂度 O ( n + log ⁡ V ) O(n+\log V) O(n+logV) ,没有卡 O ( n log ⁡ V ) O(n\log V) O(nlogV) ,好像两个 log ⁡ \log log 也过了。


AC-Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn = 2e5 + 5;

int a[maxn];
int main() {
	ios;
	int n;	cin >> n;    ll ans = 0;
	for (int i = 0; i < n; ++i)	cin >> a[i];
	sort(a, a + n);
	int tot = unique(a, a + n) - a;	// 去重
	int v1 = 0, v0 = 0xffffffff;
	for (int i = 0; i < tot; ++i) {	// 取所有的每个位置的 0和1
		v1 |= a[i];
		v0 &= a[i];
	}
	int k = v1 ^ v0;	// 得到既有0又有1的位置
	
	int i = 0;
	while (k > 0) {	// 如果存在计算,不存在的话代价就是0
		int c = 1 << i++;
		if (k & c) {
			ans = c * (tot - 1);
			break;
		}
	}
	cout << ans << endl;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值