牛客寒假算法训练营2-建通道

题目描述

输入描述:



 

输出描述:

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

输入

复制
2
1 2

输出

复制
1

说明



思路

   对于此题来说,抛去所有附加条件不管,是一个MST问题。

   然鹅对于这种数据范围,即使处理了重复的点再去建边跑KRUSKAL也是不科学的(将信将疑

   于是乎我们来思考别的解法。

   首先,毋庸置疑,肯定是去重,因为异或相同为0嘛,没有花费当然要连咯。

   其次,对于最小花费,只要全为奇数或偶数肯定是0嘛。

   说到这里肯定有很多小伙伴喷我,然鹅原题面就是这样的,后来经过和出题人一顿BBOX,他才把题面改了。。。

    

    从此时起,一切就变了。lowbit的定义变成了最低非0位(一开始写的是最低位),所以我们开始找最低的那个1在哪。

    关于这个最低的非0位,需要满足一个条件,就是在这一位上,其他所有点的权值转化为二进制后的这一位,得异或出来一个1。

    怎样才能异或出来一个1呢,相信大家大一的时候上大计基课都学过异或的口诀,“相同为0,不同为1”,所以只要所有的点权值转化为二进制后,这一位有0又有1就好啦。

    如何找到这一位呢,我们从最基础的角度思考(因为我只会点基础),利用&1的操作就可以辣,所以我们只要当找不到一个位上有0又有1时(gay圈现状),就把权值右移1位,直到找到某一位上有0又有1为止。

    如果还有不太清楚的同学可以试试去掉注释,输出过程看看,手动写写就知道了。


CODE


 1 #include <bits/stdc++.h>
 2 #define dbg(x) cout << #x << "=" << x << endl
 3 
 4 using namespace std;
 5 typedef long long LL;
 6 const int kmaxn = 3e5 + 7;
 7 
 8 int a[kmaxn];
 9 set <int> s[37];
10 int f[35][2];
11 
12 template<class T>inline void read(T &res)
13 {
14     char c;T flag=1;
15     while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
16     while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
17 }
18 
19 namespace _buff {
20     const size_t BUFF = 1 << 19;
21     char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
22     char getc() {
23         if (ib == ie) {
24             ib = ibuf;
25             ie = ibuf + fread(ibuf, 1, BUFF, stdin);
26         }
27         return ib == ie ? -1 : *ib++;
28     }
29 }
30 
31 int qread() {
32     using namespace _buff;
33     int ret = 0;
34     bool pos = true;
35     char c = getc();
36     for (; (c < '0' || c > '9') && c != '-'; c = getc()) {
37         assert(~c);
38     }
39     if (c == '-') {
40         pos = false;
41         c = getc();
42     }
43     for (; c >= '0' && c <= '9'; c = getc()) {
44         ret = (ret << 3) + (ret << 1) + (c ^ 48);
45     }
46     return pos ? ret : -ret;
47 }
48 
49 int main()
50 {
51     int n;
52     read(n);
53     for(int i = 1; i <= n; ++i) {
54        int x;
55        read(x);
56        s[0].insert(x);
57        f[0][x&1]++;
58     }
59     /*
60     printf("f[0][0]:%d f[0][1]:%d
",f[0][0],f[0][1]);
61     int d = s[0].size();
62     for(set<int> ::const_iterator p = s[0].cbegin(); p != s[0].cend(); ++p) {
63         cout << *p <<endl;
64     }
65     */
66     LL ans = 0;
67     for(int i = 0; i <= 30; ++i) {
68         if(f[i][0] && f[i][1]) {
69             ans = (s[i].size()-1) * (1 << i);
70             break;
71         }
72         for(auto it : s[i]) {
73             s[i+1].insert(it >> 1);
74             f[i+1][(it>>1)&1]++;
75         }
76         /*
77         printf("f[%d][0]:%d f[%d][1]:%d
",i,f[i][0],i,f[i][1]);
78         int d1 = s[i].size();
79         for(set<int> ::const_iterator p = s[i].cbegin(); p != s[i].cend(); ++p) {
80             cout << *p <<endl;
81         }
82         */
83     }
84     cout << ans << endl;
85     return 0;
86 }
View Code


 
原文地址:https://www.cnblogs.com/orangeko/p/12271549.html