异或

最大异或对 tire树

时间秒杀一切 提交于 2020-02-03 16:29:53
在给定的N个整数A1,A2……AN中选出两个进行xor(异或)运算,得到的结果最大是多少? 输入格式 第一行输入一个整数N。 第二行输入N个整数A1~AN。 输出格式 输出一个整数表示答案。 数据范围 1≤N≤105, 0≤Ai<231 输入样例: 3 1 2 3 输出样例: 3 直接暴力的复杂度是n²肯定是要超时的 ,知道要用字典树那么就把每个数化成二进制保存啦,因为是异或运算,相同为0不同为1 ,所以在每个节点要优先向相反位走,相反位没路了再向相同为走,为了实现最大化要从高位向低位走(wa了好几次!!!) #include<iostream> #include<map> using namespace std; const int maxn=1e5+100; int ed[maxn*32][5],idx=1;//理论上一个数有32位 实际用不到maxn*32 void insert(int x) { int p=1; for(int i=31;i>=0;i--) { int y=x>>i&1;//取出每一位的值(二进制) if(!ed[p][y]) ed[p][y]=++idx; p=ed[p][y]; } } int query(int x) { int p=1,i=31,ans=0; while(i>=0) { int y=x>>i&1; if(ed[p][1-y])

leetcode位运算

北城以北 提交于 2020-02-03 09:02:36
位运算 1,只出现一次的数字(136) 采用位运算中的异或运算,异或运算满足交换律与结合律 ^ class Solution ( object ) : def singleNumber ( self , nums ) : """ :type nums: List[int] :rtype: int """ res = 0 for i in nums : res ^ = i return res 2,颠倒二进制位(190) 采用位运算中的右移>>与左移<<操作 class Solution : # @param n, an integer # @return an integer def reverseBits ( self , n ) : res = 0 count = 32 while count : res << = 1 res += n & 1 n >> = 1 count -= 1 return int ( bin ( res ) , 2 ) 3,位1的个数(191) 采用位运算中的&操作 num&(num-1)可以消去num末尾的0 class Solution ( object ) : def hammingWeight ( self , n ) : """ :type n: int :rtype: int """ res = 0 while n : n = n & (

bzoj 2741: 【FOTILE模拟赛】L(可持久化trie + 分块优化)

时光毁灭记忆、已成空白 提交于 2020-02-01 03:25:12
预处理 a a a 数组的前缀和,问题就变成在[l - 1,r] 区间内找任意两个数,使得异或值尽可能大。 用可持久化 trie 暴力做 复杂度是 O ( 32 ∗ n ∗ m ) O(32 * n * m) O ( 3 2 ∗ n ∗ m ) 即使去掉 32 这个系数,也可能会被卡常,考虑如何优化。 考虑预处理一部分区间的答案,令 f [ l ] [ r ] f[l][r] f [ l ] [ r ] 表示 区间 [ l , r ] [l,r] [ l , r ] 的答案,显然不能预处理全部的区间,考虑分块预处理:对 l 分块(或者对 r 分块),f[l][r] 表示 从第 l 个 块的起点到 r 这段区间内 与 a[r] 异或的最大值。g[l][r] 表示 从第 l 个 块的起点到 r 这段区间内的答案。 通过 f[l][r] 和 g[l][r - 1] 可以得到 g[l][r],因此可以边搞边处理。 对于每一次询问[l,r],找到 l 所在块号的右边界 e d ed e d ,对于 [ed + 1,r] 的答案已经预处理过,枚举 [l,ed] 每一个点,在可持久化 trie 上查询 区间 [l + 1,r] 与 a[l] 异或可得到的最大值,[ed + 1,r]的答案合并即得到[l,r] 的答案。 复杂度: O ( 30 ∗ n n + 30 ∗ m ∗ n ) O(30*n

习题:changing array (贪心)

不问归期 提交于 2020-01-31 18:47:58
题目 传送门 思路 正难则反,全集是很好求的,即为 \(\frac{n*(n+1)}{2}\) ,想要异或不为0的尽可能的多,即异或为0的尽可能的少 对于所有的区间 \(l,r\) ,可以用前缀和 \(s\) 来表示, \(s_r ~xor~s_{l-1}\) , 之后我们考虑 \(xor\) 的性质,只有当两个数相同时,异或值才为0 我们设 \(t_k\) 表示有多少个前缀和为 \(k\) 对于第 \(i\) 个数,我们贪心的考虑就好了,看是不异或少,还是异或之后少就行了 贪心的正确性显然 \(t_0\) 初始值应为1,因为你还要算他本身的贡献 代码 #include<iostream> #include<map> using namespace std; int n,k; int a[200005]; map<int,int> t; int _last; long long ans; int main() { ios::sync_with_stdio(false); cin>>n>>k; k=(1<<k)-1; ans=1ll*(n+1)*n/2; for(int i=1;i<=n;i++) cin>>a[i]; t[0]=1; for(int i=1;i<=n;i++) { int u=a[i]^_last,v=a[i]^k^_last; if(t[u]<t[v]) {

csapp dataLab

大憨熊 提交于 2020-01-31 11:16:26
Datalab 1.bitXor Ops:7 设计思路: 由于异或运算的结果是相同取0,相异取1 两个数相同的方式有2种:同为1 或 同为0 计算 x&y 和 ~x&~y 上面2个式子只有2个数不同的情况下,才均为0 所以将其分别取反,再做与操作 源代码 int bitXor ( int x , int y ) { return ( ~ ( ~ x & ~ y ) & ~ ( x & y ) ) ; } 2.evenBits Ops: 4 设计思路: 目标是返回0x55555555 只能创建8个bit的数字,故int k = 0x55 将k左移8位得到0x5555 再将其左移16位得到答案 源代码 int evenBits ( void ) { int k = 0x55 ; k = k << 8 | k ; return k << 16 | k ; } 3.fitsShort Ops: 4 设计思路: 考虑到如果x可以表示为16—bit的2进制补码,则其31—15位数字全部都为1或者0 先将x右移15位,将15位以下的内容全部移除 由于int是32个bit再将ans向右移动16位,使其每个bit均为最高位,所以此时其每位要么均为1要么均为0 通过异或操作判断是否ans是否每个位置都是1或都是0 如果均为1或均为0,结果为0,逻辑非以后得到1 源代码: int fitsShort (

数组练习

微笑、不失礼 提交于 2020-01-31 10:49:14
二、题目 一个整型 数组 里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。 1、思路 大家首先想到的是顺序扫描法, 但是这种方法的时间复杂度是O(n^2)。接着大家又会考虑用哈希表的方法,但是空间复杂度不是O(1)。 应该怎么做才能即满足时间复杂度是O(n)又满足空间复杂度是O(1)的要求呢? 我们可以想一想“ 异或” 运算的一个性质,我们直接举例说明。 举例:{2,4,3,6,3,2,5,5} 这个 数组 中只出现一次的两个数分别是4和6。怎么找到这个两个数字呢? 我们先不看找到俩个的情况,先看这样一个问题,如何在一个数组中找到一个只出现一次的数字呢?比如数组:{4,5,5},唯一一个只出现一次的数字是4。 我们知道异或的一个性质是: 任何一个数字异或它自己都等于0 。也就是说 ,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字。 比如数组{4,5,5},我们先用数组中的第一个元素4(二进制形式:0100)和数组中的第二个元素5(二进制形式:0101)进行异或操作,0100和0101异或得到0001,用这个得到的元素与数组中的三个元素5(二进制形式:0101)进行异或操作,0001和0101异或得到0100,正好是结果数字4。这是因为数组中相同的元素异或是为0的,

找出2n+1个数中不成对的那个

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-31 09:35:04
问题定义: 有2n+1个数,只有一个单着,别的都是成对的,找出这个单着的数。比如:2 1 3 2 1。3是答案。 思路一: 暴力搜索——每个数都和其他数比较,找不到相同的,就得到了结果。时间复杂度为o(n 2 ) 思路二: 排序搜索——先给序列排个序,之后从前往后一对一对的找,直到不是成对的为止。时间复杂度,怎么也得o(nlgn) 思路三: 异或计算,一趟搞定。时间复杂度o(n) 直接看思路三: 原理: 异或操作(^)——(对于 位 操作)相同为0,相异为1.比如:1^0 = 1, 1 ^1=0 这样: 两个相同的数异或就为0 任何数和0异或为自己(转化到位。 1 ^0 = 1 , 0 ^0= 0 ) 例如: 5 ^ 5 = 0 5 ^ 0 = 5 对于本题:2 1 3 2 1,都异或一下:相同的(2^2,1^1) 为0,剩下的3和0异或为自身3。 (注: 异或具有 交换律 ) 参考代码: #include <stdio.h> int main() { int a[5] = {2, 1, 3, 2, 1}; int aim = a[0]; for(i = 1; i < 5; i++) { aim = aim ^ a[i]; } printf("Result:", aim); return 0; } 异或在这方面挺好,再来个应用: 不用第三个数直接交换两个数: #include

C#位运算 示例

你说的曾经没有我的故事 提交于 2020-01-31 06:04:52
在C#中可以对整型运算对象按位进行逻辑运算。按位进行逻辑运算的意义是:依次取被运算对象的每个位,进行逻辑运算,每个位的逻辑运算结果是结果值的每个位。 C#支持的位逻辑运算符如表2.9所示。 运算符号 意义 运算对象类型 运算结果类型 对象数 实例 ~ 位逻辑非运算 整型,字符型 整型 1 ~a & 位逻辑与运算 2 a & b | 位逻辑或运算 2 a | b ^ 位逻辑异或运算 2 a ^ b >> 位右移运算 2 a>>2 1、位逻辑非运算 位逻辑非运算是单目的,只有一个运算对象。位逻辑非运算按位对运算对象的值进行非运算,即:如果某一位等于0,就将其转变为1;如果某一位等于1,就将其转变为0。 比如,对二进制的10010001进行位逻辑非运算,结果等于01101110,用十进制表示就是: ~145等于110;对二进制的01010101进行位逻辑非运算,结果等于10101010。用十进制表示就是~85等于176。 2、位逻辑与运算 位逻辑与运算将两个运算对象按位进行与运算。与运算的规则:1与1等于1,1与0等于0。 比如:10010001(二进制)&11110000等于10010000(二进制)。 3、位逻辑或运算 位逻辑或运算将两个运算对象按位进行或运算。或运算的规则是:1或1等1,1或0等于1, 0或0等于0。比如10010001(二进制)| 11110000(二进制

C# 中的位运算

ε祈祈猫儿з 提交于 2020-01-31 05:54:15
在C#中可以对整型运算对象按位进行逻辑运算。按位进行逻辑运算的意义是:依次取被运算对象的每个位,进行逻辑运算,每个位的逻辑运算结果是结果值的每个位。C#支持的位逻辑运算符如表2.9所示。 运算符号 意义 运算对象类型 运算结果类型 对象数 实例 ~ 位逻辑 非 运算 整型,字符型 整型 1 ~a & 位逻辑 与 运算 2 a & b | 位逻辑 或 运算 2 a | b ^ 位逻辑 异或 运算 2 a ^ b << 位 左移 运算 2 a<<4 >> 位 右移 运算 2 a>>2 1、 位逻辑非运算 位逻辑非运算是单目的,只有一个运算对象。位逻辑非运算按位对运算对象的值进行非运算,即:如果某一位等于0,就将其转变为1;如果某一位等于1,就将其转变为0。 比如,对二进制的10010001进行位逻辑非运算,结果等于01101110,用十进制表示就是: ~145等于110;对二进制的01010101进行位逻辑非运算,结果等于10101010。用十进制表示就是~85等于176。 2 、位逻辑与运算 位逻辑与运算将两个运算对象按位进行与运算。与运算的规则:1与1等于1,1与0等于0。 比如:10010001(二进制)&11110000等于10010000(二进制)。 3、 位逻辑或运算 位逻辑或运算将两个运算对象按位进行或运算。或运算的规则是:1或1等1,1或0等于1, 0或0等于0

C#位运算

ぃ、小莉子 提交于 2020-01-31 05:24:56
C#位运算 在C#中可以对整型运算对象按位进行逻辑运算。按位进行逻辑运算的意义是:依次取被运算对象的每个位,进行逻辑运算,每个位的逻辑运算结果是结果值的每个位。C#支持的位逻辑运算符如表2.9所示。 运算符号 意义 运算对象类型 运算结果类型 对象数 实例 ~ 位逻辑 非 运算 整型,字符型 整型 1 ~a & 位逻辑 与 运算 2 a & b | 位逻辑 或 运算 2 a | b ^ 位逻辑 异或 运算 2 a ^ b << 位 左移 运算 2 a<<4 >> 位 右移 运算 2 a>>2 1、 位逻辑非运算 位逻辑非运算是单目的,只有一个运算对象。位逻辑非运算按位对运算对象的值进行非运算,即:如果某一位等于0,就将其转变为1;如果某一位等于1,就将其转变为0。 比如,对二进制的10010001进行位逻辑非运算,结果等于01101110,用十进制表示就是: ~145等于110;对二进制的01010101进行位逻辑非运算,结果等于10101010。用十进制表示就是~85等于176。 2 、位逻辑与运算 位逻辑与运算将两个运算对象按位进行与运算。与运算的规则:1与1等于1,1与0等于0。 比如:10010001(二进制)&11110000等于10010000(二进制)。 3、 位逻辑或运算 位逻辑或运算将两个运算对象按位进行或运算。或运算的规则是:1或1等1,1或0等于1,