zoukankan      html  css  js  c++  java
  • 位运算之巧解

    上班打卡

    Problem Description:

    某公司上班使用打卡制度,员工需要在打卡机器上打入和打出才算上班。每个员工都有自己对应编号K,编号为一个整数(1 <= K <=50000),某天有一员工忘记了一次打出。现在给你当天员工的打卡信息,你能找出该员工的编号吗?

    Input:

    输入包含多组测试,第一行包含数字N,表示公司的人数(1<=N<=50000)。第二行有2N-1个数,两两之间有空格,表示所有员工的打卡记录。输入N为0则退出程序,不做输出。
    

    Output:

    对于每组测试,单独一行输出忘记打卡员工的编号。

    Sample Input:

    4
    10 12 9 12 250 9 10
    

    Sample Output:

    250
    解题思路:给出2n-1个数,其中有n个数出现的次数都为2,剩下的1个数出现的次数为1,要求快速找出这个数。通过异或运算的特点可知,①自己异或本身的值为0,②任何数和0异或都为其本身。因此异或所有出现次数为2的数最终的值为0,那么就只剩下出现次数为1的元素。
    AC代码:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,x,ans;
     4 int main(){
     5     while(cin>>n&&n){
     6         n=2*n-1,ans=0;
     7         while(n--){cin>>x;ans^=x;}
     8         cout<<ans<<endl;
     9     }
    10     return 0;
    11 }

    小白刷分记(二)

    Problem Description:

    小白最近刷听力,刷出了一个大麻烦。不知为何刷出了负分,小白只能向大白求助。
    无奈大白翻车了。所以小白向小光师公求助,小光师公说只要你帮我解决了下面这道题目,
    我就帮你刷回正分。无奈小白不会,只能交给聪明的你来解决了。
    数组A中,除了某一个数字x之外,其他数字都出现了三次,
    而x出现了一次。请给出最快的方法找到x。 

    Input:

    先输入n,表示要输入n个数字。( 0< n < 10^8)
    然后输入n个数字m。(-10^8)< m <(10^8)

    Output:

    输出x

    Sample Input:

    10
    2223 1 1 2223 1 -111 1 2223 1 1
    4
    5 5 5 -6

    Sample Output:

    -111
    -6
    解题思路:给出n个数,其中有(n-1)/3个数出现的次数都为3,剩下的1个数出现的次数为1,要求快速找出这个数。考虑每个数的二进制,因为每个数出现的次数都为3,所以32位二进制中每个bit上'1'的统计结果都可以被3整除,否则就是出现次数为1的数在这个bit上贡献出多余的1。因此,将每个数转化成其二进制,并且统计每个bit上1的个数,然后累加某个bit上不能被3整除的十进制数1<<bit,最终即可得到出现次数为1的数字。
    推广一下,所有其他数字出现n(n>=2)次,而一个数字出现1次都可以用这种解法来推导出这个出现1次的数字。

    AC代码:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,x,ans,bits[32];
     4 int main(){
     5     while(~scanf("%d",&n)){
     6         ans=0;memset(bits,0,sizeof(bits));
     7         for(int i=1;i<=n;++i){
     8             scanf("%d",&x);
     9             if(!x)continue;
    10             for(int j=0;j<32;++j)bits[j]+=((x>>j)&1);//要用右移操作,便于正确计算和避免溢出
    11         }
    12         for(int i=0;i<32;++i)
    13             if(bits[i]%3!=0)ans+=(1<<i);//累加二进制上对应的值
    14         printf("%d
    ",ans);
    15     }
    16     return 0;
    17 }

    NYOJ #744 蚂蚁的难题(一)

    描述

    小蚂蚁童鞋最近迷上了位运算,他感觉位运算非常神奇。不过他最近遇到了一个难题:

    给定一个区间[a,b],在区间里寻找两个数x和y,使得x异或y最大。来,帮帮他吧!

    输入

    有多组测试数据(以EOF结尾)。
    每组数据输入两个数a,b.(0<=a<b<2^63)。

    输出

    输出a到b之间,异或最大的值。

    样例输入

    1 2
    8 9

    样例输出

    3
    1

    解题思路:为了异或得到最大值,我们应选择某两个数的二进制位是互补的,并且其中一个数的二进制最高位的'1'是区间所有数的二进制中相对较高位的'1',这样就能得到全是1的二进制数,其位数为bits,则得到的异或值为2bits-1。于是,通过异或区间左右端点的值a^b可以发现,如果a和b二进制的前几位是相同的,那么在a到b的所有数中,这前几位都不会改变,即无论选什么数进行异或,这前几位都是0,而后面的每个bit里0和1都可能出现,并且一定能找到互补的两个数使其异或后后面的几个bit都是1,这便可得到最大值;同理如果a、b的最高位不同,那么此时取决于b的二进制位数,因为b中某些bit为0的位一定能通过区间中某个数的二进制bit进行'1'互补,即得到全为1的那几位。因此只需要找到a和b的二进制从高位往后数第一个不相同的位,然后如果余下m位,那么答案就是2m-1。

    AC代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;LL a,b;
     4 LL get_bits(LL x){//得到异或的值的二进制位数
     5     LL bits=1;
     6     while(x>>=1)bits++;
     7     return bits;
     8 }
     9 int main(){
    10     while(cin>>a>>b){
    11         cout<<((1LL<<get_bits(a^b))-1)<<endl;//2^n-1
    12     }
    13     return 0;
    14 }
     
  • 相关阅读:
    IntelliJ IDEA 14.03 java 中文文本处理中的编码格式设置
    应聘感悟
    STL string分析
    CUDA SDK VolumeRender 分析 (1)
    BSP
    CUDA SDK VolumeRender 分析 (3)
    CUDA SDK VolumeRender 分析 (2)
    Windows软件发布时遇到的一些问题
    Ten Commandments of Egoless Programming (转载)
    复习下光照知识
  • 原文地址:https://www.cnblogs.com/acgoto/p/9823298.html
Copyright © 2011-2022 走看看