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<。
异或就是把两个数转换成二进制,进行相同位上的运算,
相同为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\n", 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\n", ans^r);
}
return 0;
}