• 牛客寒假算法训练营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
    
    
    
     
  • 相关阅读:
    2018年国内就业薪资高的7大编程语言排行
    前端css实现最基本的时间轴
    前端css实现最基本的时间轴
    用Canvas画一个刮刮乐
    用Canvas画一个刮刮乐
    「干货」从菜鸟到大神,前端学习书籍推荐
    洛谷P3379 【模板】最近公共祖先(LCA)
    洛谷 P1359 租用游艇
    位运算...
    洛谷P2782 友好城市
  • 原文地址:https://www.cnblogs.com/orangeko/p/12271549.html
Copyright © 2020-2023  润新知