zoukankan      html  css  js  c++  java
  • 异或运算的运用

    背景1:最多有1e6+1个数,其中只有一个数出现了奇数次,请找出这个数(数据大小为 int 范围)

    利用原理:两个相同的数异或值为0

    解决方案:将所有数异或一次,最后得到的值就是出现奇数次的那个数

    复杂度O(n)

    背景2:最多有1e6个数,其中有两个数出现了奇数次,请找出这两个数(数据大小为 int 范围)

    利用原理仍然是两个相同的数异或值为0,不过还需要我们考虑到的是,首先这两个数肯定不同,

    否则相同的两个数分别出现奇数次,最后就是这个数出现了偶数次(与题意矛盾)

    所以我们可以得到的是将所有数异或一遍以后会得到一个非零数,而这个非零数有重要的性质

    如果我们把这个数转化为二进制数,例如下面这个数

                         0 0 1 0 1 1 0

    我们观察为1的那三位,选出其中一位来,比如可以选倒数第2位,那么要使这一位最后异或结果为1

    那么我们需要奇数个倒数第2位为1的数(二进制)相异或才能使最后的结果为1,说明出现奇数次的两个
    数中,其中必定有一个数的二进制倒数第2位为1,另一个数二进制倒数第2位为0。

    反证一下,如果两个数二进制倒数第2位都为1或都为0,那么最后异或的次数为(奇+奇+其他出现偶数次的数==偶数次)

    最后倒数第二位应该为0,相互矛盾,所以原命题正确。

    有这个结论后,我们只需要再将所有二进制倒数第2位为1的数异或起来,就得到了题目要求的其中一个数,

    将这个数与最开始所有数异或以来得到的值进行一下异或就得到了另一个数

    复杂度O(n)

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <cstring>
     7 #include <stack>
     8 #include <cctype>
     9 #include <queue>
    10 #include <string>
    11 #include <vector>
    12 #include <set>
    13 #include <map>
    14 #include <climits>
    15 #define lson root<<1,l,mid
    16 #define rson root<<1|1,mid+1,r
    17 #define fi first
    18 #define se second
    19 #define ping(x,y) ((x-y)*(x-y))
    20 #define mst(x,y) memset(x,y,sizeof(x))
    21 #define mcp(x,y) memcpy(x,y,sizeof(y))
    22 using namespace std;
    23 #define gamma 0.5772156649015328606065120
    24 #define MOD 1000000007
    25 #define inf 0x3f3f3f3f
    26 #define N 500050
    27 #define maxn 100001
    28 typedef pair<int,int> PII;
    29 
    30 int n,a[1000005];
    31 
    32 int main(){
    33     int i,j,group,x,y;
    34     scanf("%d",&group);
    35     while(group--){
    36         scanf("%d",&n);
    37         int temp=0;
    38         for(i=1;i<=n;++i){
    39             scanf("%d",&a[i]);
    40             temp^=a[i];
    41         }
    42         if(n==2){
    43             if(a[1]>a[2])swap(a[1],a[2]);
    44             printf("%d %d
    ",a[1],a[2]);
    45             continue;
    46         }
    47         int cnt=0;
    48         while(1){
    49             if(temp&(1<<cnt))break;
    50             cnt++;
    51         }
    52         int ans1=0;
    53         int k=1<<cnt;
    54         for(i=1;i<=n;++i){
    55             if(a[i]&(k))
    56                 ans1^=a[i];
    57         }
    58         int ans2=temp^ans1;
    59         if(ans1>ans2)swap(ans1,ans2);
    60         printf("%d %d
    ",ans1,ans2);
    61     }
    62     return 0;
    63 }
  • 相关阅读:
    使用jenkins发布docker容器
    使用jenkins构建和部署前端(jenkins是k8s集群中搭建)
    kubernetes的ingress-nginx使用案例
    使用jenkins的SSH Publishers远程执行
    kubernetes集群:向pod里的/etc/hosts添加解析
    kubernetes集群:nacos搭建
    JavaBean的概念
    Statement与PreparedStatement的区别
    JDBC的概念&使用步骤
    session的用法
  • 原文地址:https://www.cnblogs.com/Kurokey/p/5576774.html
Copyright © 2011-2022 走看看