zoukankan      html  css  js  c++  java
  • 1223:An Easy Problem

    1223:An Easy Problem 题目链接

    题目的要求是:

    **要使得 n 在 a 不变的情况下 ,得到任意多的 n' 满足 n' > n ,定义为集合 M ,要求取 M 中最小的 n' 为 **

    (a 代表 n 中二进制位 为 1 的个数)

    • 一种暴力做法是,统计 n 的二进制中 1 的个数为 a ,然后 设置一个变量 t = n,t 每次自增 1 (t++),

      之后,统计 t 的二进制中 1 的个数为 b , 如果 a == b,那么 t 就是 比 n 大的正整数集合 M 中,最小的数。

    • O(1) 的做法是用位运算,举个例子 :

      n == 78,我们尝试着在不改变 a 的情况下,移动 n 的二进制中的 1 , 让 n 变大的幅度尽可能的小

      序号 n n 中的二进制表示
      1 78 ‭0100 1110‬
      2 77 0100 1101
      3 89 0101 0101
      4 83 ‭0101 0011‬
      • 为了实现变大的过程,肯定要把 某个 1 向左移动,那么如何选取这个 1 呢?

        从右边开始 寻找第一段 连续的 1 (只有一个 1 也算 一段), 把将这段连续 1 中最左端的 1 向左前进 一 位

        要让这段连续 1 中的左端 前进一位 ,只要在 这段连续的 1 的右端 加 1就好了,二进制的加法进位到头

        如何寻找 右端的 1 呢?

        lowbit运算 : t1 = n & (-n) 得到最右边的 1

        ​ ‭0100 1110‬

        ​ & 1011 0010

        ​ = 0000 0010

        之后 t2 = n + t1; 得到进位之后的值。

        ​ ‭ 0100 1110‬

        ​ + 0000 0010

        ​ = 0101 0000

        但是,这么做了之后,我们就丢失了 原先那段连续 的 1 的信息了。

      • 为了让 n 变大的 幅度尽可能的小

        就要把那一段连续的 1 剩余的部分,全部移动到 最右边 (参考 序号 1 和 序号 4 的二进制表示)

        寻找那段丢失的 1 。

        ​ n ^ t2

        ​ 0100 1110‬

        ​ ^ 0101 0000

        ​ = 0001 1110

        我们发现,这样 经过 ^ 得到的结果,会多出两个 1 ,解法办法是,右移的时候,再向右移动两位就好

        即 >> 2

        (n ^ t2) / t1 ,( / t1) 这个操作是为了把 ^ 之后的 1 整个向右移动 (log_2 t1) 的位置,

        因为 t1 代表了 最右边的 1 ,且只有 1 ,在二进制表示中,肯定是 2的幂,(log_2 t1) 得到当前t1 中 1的位置

        / t1 相当于 >>(log_2 t1) ,两者相等, 之后再 >>2 消去多余的 两个 1 ,

        最后 和 t2 取 按位或 就得到了最终想要的结果。

    代码实现

    #include <bits/stdc++.h>
    using namespace std;
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0),cout.tie(0);
        int x,t1,t2,y;
        while(cin>>x){
            if(x == 0) break;
            t1 = x & (-x);  
            t2 = x + t1;
            y = t2 | ((x ^ t2) / t1) >> 2;
            cout<<y<<endl;
        }
        return 0;
    }
    

    参考: https://blog.csdn.net/u012891472/article/details/52641838

  • 相关阅读:
    Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2)
    Codeforces Round #592 (Div. 2)
    日常杂谈
    vc_redist x64 或者x86下载地址
    windows terminal编译实录
    刷机,twrp,安装xposed
    博客迁移公告
    tcpdump实用笔记
    分享一篇企鹅的暑期实习生技术面经验
    visudo使用笔记
  • 原文地址:https://www.cnblogs.com/lukelmouse/p/10739007.html
Copyright © 2011-2022 走看看