11076: 小P的集合 位运算

考虑当只有一个数出现奇数次的时候,我们可以很轻松的知道,把所有的数异或和即可,因为异或运算有一个非常有意思的性质,a^b^a=b

考虑当有两个数(a,b)出现奇数次的时候,我们异或和得到,num=a^b,那么怎么把这两个数分开呢?

我们想想,既然是位运算,一定和二进制有关,我们把num的二进制展开,我们发现一个问题,这个数的二进制为1的位置,一定是a或者b上的二进制异或留下,

那么我们可以知道,这位二进制位,要么a是1,要么b是1。

因此我们枚举这给的数的二进制位,看是否为1,如果为1,如果所有数的异或和在这一位二进制为1,代表对答案位置的二进制可能有贡献(也有可能被异或掉了),我们用cnt[i]代表这个二进制位,代表对i位的二进制影响。

cnt[i]:异或每一个对这一位有影响的数,他们的异或和只可能有三种张结果。要么是a,b中一个,要是sum(代表包括a,b在内的数对这一位是1都有贡献),或者是0。

我们再次枚举所有异或和的二进制,如果这一位为1,那么这一位的cnt[i],一定不可能同时存在a,b,但是也一定不可能没有a,b。所以这一位的cnt[i]保存的一定是a,b中的一个。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#define LL long long
using namespace std;
LL cnt[40];
LL n;
LL k;
LL sum=0;
int main(){
  while(~scanf("%lld%lld",&n,&k)){
     LL tmp;
     sum=0;
     for (int i=0;i<n;i++){
        scanf("%lld",&tmp);
        for (int j=0;j<32;j++){
            if((1<<j)&tmp){
                cnt[j]^=tmp;
            }
        }
        sum^=tmp;
     }
     if (k==1){
        printf("%lld\n",sum);
        continue;
     }
     LL a=0;
         for (int i=31;i>0;i--){
            if((1<<i)&sum){
                a=sum^cnt[i];
                break;
            }
          }
          printf("%lld %lld\n",a,sum^a);
  }
  return 0;
}

原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10424983.html

时间: 2024-10-11 16:27:55

11076: 小P的集合 位运算的相关文章

位运算大集合

一.位运算常用的小技巧:判断奇偶.交换两数.变换符号及求绝对值等 1.判断奇偶 只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数.因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数. 下面程序将输出0到100之间的所有奇数. 1 for (i = 0; i < 100; ++i) 2 if (i & 1) 3 printf("%d ", i); 4 putchar('\n'); 2.交换两数 一般的写法是:

求集合中选一个数与当前值进行位运算的max

求集合中选一个数与当前值进行位运算的max 这是一个听来的神仙东西. 先确定一下值域把,大概\(2^{16}\),再大点也可以,但是这里就只是写写,所以无所谓啦. 我们先看看如果暴力求怎么做,位运算需要给定\(01/10,00,11\)的关系,总共\(8\)种. 如果是暴力的话,我们的方法有两种, 第一种是比较喜闻乐见的, 我们对于当前数\(x\),暴力计算所有存在的数\(a_i\)中,\(x\oplus a_i\)的最大值,这样的复杂度是\(O(2^{16})\)的. 另外一种也是不难考虑到的

位运算之——按位与(&amp;)操作——(快速取模算法)

由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快. 按位与(Bitwise AND),运算符号为& a&b 的操作的结果:a.b中对应位同时为1,则对应结果位也为1. 例如: 10010001101000101011001111000 & 111111100000000 --------------------------------------------- 10101100000000 对10101100000000进行右移8位得到的是101011,这就得

数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算

参考:浙大数据结构(陈越.何钦铭)课件 1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找——方法一:顺序查找(时间复杂度O(n)) int

STL+位运算的文件

1.queue 队列 queue的头文件是<queue>. 定义queue对象的示例代码如: queue<int>q;  队列内存放的是int类型的数 queue<double> 队列内存放的是double类型的数 queue<node>q;  队列内存放的是结构体类型 入队列:q.push(x)   将x元素放到队列的末端. 出队列:q.pop()    将第一个元素删除 访问队首元素: q.front(); 访问队中的元素的个数: q.size(); 2

【数据结构】树与树的表示、二叉树存储结构及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树与哈夫曼编码、集合及其运算

1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找--方法一:顺序查找(时间复杂度O(n)) int SequentialSearch(St

Java I/O : Bit Operation 位运算

Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆         瓣:BYSocket FaceBook:BYSocket Twitter    :BYSocket 泥瓦匠喜欢Java,文章总是扯扯Java. I/O 基础,就是二进制,也就是Bit. 一.Bit与二进制 什么是Bit(位)呢?位是CPU处理或者数据存储最小的单元.类似于很小很小的开关,一开一关,表示为1或者0.所以,这就是计算机处理任何数据的"细胞",要谨记.

C言语位运算

所谓位运算,就是对一个比特(Bit)位停止操作.在<二进制思惟以及数据的存储>一节中讲到,比特(Bit)是一个电子元器件,8个比特组成一个字节(Byte),它曾经是粒度最小的可操作单位了.C言语供给了六种位运算符: 运算符 & | ^ ~ << >> 阐明 按位与 按位或 按位异或 取反 左移 右移 按位与运算(&) 一个比特(Bit)位只要 0 和 1 两个取值,只要介入&运算的两个位都为 1 时,后果才为 1,不然为 0.例如1&1为

位运算的妙用

位运算所有语言里面都有位运算,&,|,^,~,<<,>>,>>>,但是其他语言不清楚,前端估计许多人直接一扫而过,甚至把这玩意和逻辑或与混淆,甚至有的不认识<<,>>>,问这什么意思的那是许多许多.由于这个运算属于底层的二进制的运算,不做详解(详解的话,阅读不易,而且许多人功力不够),只讲一些常用的,(注意位运算性能更好,且容易装逼,稳重的装逼)1.判断奇偶数常用的(a%2!=0)位运算 if(a&1){奇数}原理:任