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

  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/lukelmouse/p/10739007.html
Copyright © 2011-2022 走看看