Problem H: 《为什么会变成这样呢》
Description
“第一次有了喜欢的人,还得到了一生的挚友,两份喜悦互相重叠,这双重的喜悦又带来了更多更多的喜悦,本应已经得到了梦幻一般的幸福时光,然而,为什么,会变成这样呢?”双重的喜悦感却无法带来更多的幸福,现在,雪菜在很多喜悦感之中只想要得到两份不重叠的喜悦感(其他的喜悦感都是重叠的),你能帮她找出这两份不同的喜悦感是多少吗?
Input
第一行一个整数T,代表数据的组数(1<=T<=10),接下来T组数据,每组数据的第一行是一个整数n(1<=n<=1000000),第二行是n个整数ai(0 <= ai <= 1000000000)代表喜悦感,每两个整数之间有一个空格,题目保证有且仅有两个不同的整数出现一次,其他的整数都是出现两次。
Output
对于每组数据,输出两个整数,分别代表两份不同的喜悦感,中间有一个空格,并且喜悦感较小的先输出。
Sample Input
2
6
2 2 1 1 3 4
4
1 1 3 4
Sample Output
3 4
3 4
【分析】
一道经典题的拓展,我做过的题目是只有一个数出现一次。
如果只有一个数出现一次,那么很简单,整个数组异或一遍,得出的结果就是出现过一次的题目。
只需要记得
0⊕A=A A⊕A=0
A⊕B=B⊕A
(A⊕B)⊕C=A⊕(B⊕C)
这道题因为有两个数出现过一次。
所以不能简单的异或整个数组,这个时候异或整个数组。得出的结果是这两个数的异或结果。
那么我们可以考虑,把这n个数分成两组,分别异或,就可以得到这两个数。
显然,出现两次的数不用考虑,因为它们不管分在哪一组,都对结果没有任何影响,所以要考虑的是,如何将这两个数分到两组中去。
这两个数异或结果中为0的位说明两个数在这个二进制位上表示相同,那么只要找到第一个表示不同的位置,就可以将这两个数区分开了。
找到第一位为1的位置xx
然后对对每个数的二进制位中xx这个位置进行判断,0的为一组,1的为一组。两组分别异或就可以求出答案。
【代码】
#include <stdio.h>
int a[2010000];
int main()
{
int pp;scanf("%d",&pp);
while (pp--)
{
int n;scanf("%d",&n);
int ans=0;
int A=0,B=0;
for (int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
ans^=a[i];
}
int xx=0;
while (ans)
{
if (ans%2==1) break;
xx++;
ans/=2;
}
for (int i=0;i<n;i++)
{
int x=1 & (a[i] >> xx);
if (x)
A^=a[i];
else
B^=a[i];
}
if (A>B) {int t=A;A=B;B=t;}
printf("%d %d\n",A,B);
}
return 0;
}
int a[2010000];
int main()
{
int pp;scanf("%d",&pp);
while (pp--)
{
int n;scanf("%d",&n);
int ans=0;
int A=0,B=0;
for (int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
ans^=a[i];
}
int xx=0;
while (ans)
{
if (ans%2==1) break;
xx++;
ans/=2;
}
for (int i=0;i<n;i++)
{
int x=1 & (a[i] >> xx);
if (x)
A^=a[i];
else
B^=a[i];
}
if (A>B) {int t=A;A=B;B=t;}
printf("%d %d\n",A,B);
}
return 0;
}