zzuli1519: 小P参加相亲大会(异或)

http://acm.zzuli.edu.cn/problem.php?id=1519

题目描述

小P最近人生得意,去参加了一次相亲大会,相亲大会上每个人有一个密码牌(密码牌上的密码是一个正整数m,m<231 ),相互之间在交流之前先交换密码牌,密码牌上的密码可能相同,也可能不同,如果相同,两人牵手离开,如果不保同,各自再寻找下一位,保证最后只有1个人或2个人留下来。
 

输入

第一行两个数 n,k (n≤3000000,1≤k≤2),n表示参加相亲大会的人数,接下来 n行每行一个正整数表示相亲大会上每一个人的密码,k表示最后留在相亲大会的人数。

输出

从小到大输出一行 k个数,表示相亲不成功留在相亲大会人的密码,中间用空格分隔。

样例输入 Copy

3 1
2
2
2

样例输出 Copy

2

提示

对于40% 的数据,保证 k=1。

对于20%的数据,保证n≤100

对于100%的数据,保证 n≤3000000,ai<2^{31}

异或就是把两个数转换成二进制,进行相同位上的运算,

相同为0,不同为1

也就是说相同的数异或为0,与0异或为本身。

a^a=0, a^0=a;

如果是在给出的数中找出一个出现奇数次的数,只需要把所有的数异或剩下最后的那个数就是答案。

但是这道题有两个数的情况,下面说的是两个数的情况:

还是先把所有的数异或一下,最后得出的数是两个应该输出的两个数异或的结果k。

把这个数转换成二进制,找出为1的位,要输出的两个数这个位一个为0,一个为1。

再遍历一次数组,把相应位上为1(或0)的数再异或一遍,最后得到两个数中的一个a。

再将k和a异或得到另一个答案b。

用到的公式:

k=a^b;

a=k^b=a^b^b

b=k^a=a^b^a

#include<stdio.h>
#define N 3000020
int a[N];
int main()
{
	int n,k,i,ans=0,r,t;
	scanf("%d%d", &n, &k);
	for(i=0; i<n; i++)
	{
		scanf("%d", &a[i]);
		ans^= a[i];
	}
	if(k == 1)
		printf("%d
", ans);
	else
	{
		r=ans;
		t=1;
		while(!(r%2))
		{
			r/=2;
			t*=2;
		}
		r=ans;
		for(i=0; i<n; i++)
			if((a[i]/t)%2)
				ans^= a[i];
		printf("%d ", ans);
		printf("%d
", ans^r);
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/zyq1758043090/p/11852782.html