【总结】异或知识积累

「MtOI2019」永夜的报应

辉夜手里有 n \rm{n} n个非负整数 a \rm{a} a1, a \rm{a} a2, …… a \rm{a} an;

由于辉夜去打 Gal Game 去了,她希望智慧的你来帮忙。

  • 你需要将这些数分成若干组,满足 n \rm{n} n个数中的每一个数都恰好被分到了一个组中,且每一组至少包含一个数。

定义一组数的权值为该组内所有数的异或和。请求出一种分组方案,使得分出的所有组数的权值之和最小,输出权值之和的最小值。

分析:
我们知道^为异或运算,而异或运算有一个性质:

a^b<=a+b

所以无论怎样分,结果是肯定不大于全部异或的值。

#include<cstdio>
int n,x,ans;
int main() {
    
    
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
    
    
		scanf("%d",&x);
		ans^=x;
	}
	printf("%d",ans);
}

资料:

题目1:

一个整型数组里除了1个数字出现 奇数次 外,其他数字都出现 偶数次 ,请找出 只出现奇数次的 这个数。

要求: 时间复杂度 O(n) ,空间复杂度 O(1)。

解题思路:

1、我们知道 2个相同的数异或的结果为0, 所以我们将这n个数从头到尾 异或一遍得到结果x

2、于是乎,我们便得到了结果……

题目2:

一个整型数组里除了两个数字出现 奇数次 外,其他数字都出现 偶数次 ,请找出 只出现奇数次的 这两个数。

要求: 时间复杂度 O(n) ,空间复杂度 O(1)。

解题思路:

根据题目1,我们可以想到,能不能将这两个数分开呢……

1、我们将这n个数从头到尾 异或一遍得到结果x

2、根据x的二进制表示中不为1的某一位,位置为y,然后将这n个数分成两类:y位置为1和y位置为0

3、将这两类数分别异或得到两个数a和b,便是我们所要求得结果

  • 首先出现奇数次的这两个数可定时不想等的,

  • 所以两个出现奇数次的数在y位置上的二进制表示肯定是不同的,

  • 否则y位置的结果不可能为1。

  • 这样便将这两个数分开了。

  • 又因为,每一类数中的其他数异或之后肯定为0,

  • 所以,便得到结果啦……

题目3:

给你1到n这n个数,无序,现将其中一个数x改变成y,找出这两个数

要求: 时间复杂度 O(n) ,空间复杂度 O(1)。

解题思路:

刚开始想排序,不过O(n)的复杂度,很难(⊙o⊙)哦 ,根据上一题,可以这么考虑:
相当于我们有了两个数组,题目中所给的一个和从1到n这个有序的数组,然后就跟上一题一样(≧▽≦)/啦啦啦

1、求出1到n的异或值x

2、继续将x与题目中所给的所有数值异或,得到新的x

3、根据x的二进制表示中不为1的某一位置y,然后将这n*2个数分成两:y位置为1和y位置为0

4、将这两类数分别异或得到两个数a和b,便是我们所要求得结果


问题:求1到n这n个整数间的异或值,即 1 xor 2 xor 3 … xor n
定理:

f(1, n) = f(0, n) =

n : n % 4 == 0

1 : n % 4 == 1

n +1 : n % 4 == 2

0 : n % 4 == 3

可以用数学归纳法予以证明

#include<cstdio>
int n,tot;
int main() {
    
    
	for(int n=2;n<=100;n++) {
    
    
		int t = n & 3;
		//取出整数n在二进制表示下的第0~k-1位:n & ( ( 1 << k ) - 1 ) 
        if (t & 1) tot= (t / 2) ^ 1;
        else tot= (t / 2) ^ n;
        printf("%d:%d\n",n,tot);
	}
}

猜你喜欢

转载自blog.csdn.net/cqbzlydd/article/details/104214577
今日推荐