序列中,除了2个数字只出现一次外,其他数字成对出现。找出落单的2个数。

时间:2021-12-01 14:32:07

本题是上一题的续篇,扩展篇。 同时也是jobdu1351题。

想把这一问题先转化为上一个问题,然后解决掉。于是需要将序列分成2类,正好把两个落单的数划分到两个类中去

1,位运算的优先级真是搞不清楚。以后遇上^&|<<>>,这样的运算外都用小括号括上。 if((a[i]&cls) == 0) 这句话 如果不给&加上小括号,就会出错。

2,第一次先把序列异或起来,得到的结果其实就是两个落单的数的异或。分析结果,结果的二进制中为1的位为这两个数不同的,从中随便选一个位作为“分类标准”(我选的是最右边的1)。

3,分类之后,就变为上一问题了(序列中只有一个落单的数)。根据分类标准,将各类中的数字异或起来。就得到了两个落单的数。



#include<cstdio>
#include<iostream>
using namespace std;

int main()
{
int n;
unsigned int sum=0;
scanf("%d",&n);
if(n%2)
{
printf("impossible!\n");
return 0;
}
int *a = new int[n];

for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum ^= a[i];
}
//printf("%d\n", sum);

unsigned int index = 0;
while(sum)
{
if(sum&1 == 1)
break;
sum = sum>>1;
index++;
}
unsigned int cls = (1<<index);
int result1=0,result2=0;
for(int i=0;i<n;i++)
{
if((a[i]&cls) == 0)
result1 ^= a[i];
else
result2 ^= a[i];
}

if(result1 < result2)
printf("%d %d\n", result1, result2);
else
printf("%d %d\n", result2, result1);


delete[] a;
a=NULL;
return 1;

}



//1351
#include<cstdio>
#include<iostream>
using namespace std;

int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
if(n%2)
{
printf("impossible!\n");
return 0;
}
int *a = new int[n];
unsigned int sum=0;

for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum ^= a[i];
}

unsigned int index = 0;
while(sum)
{
if(sum&1 == 1)
break;
sum = sum>>1;
index++;
}
unsigned int cls = (1<<index);
int result1=0,result2=0;
for(int i=0;i<n;i++)
{
if((a[i]&cls) == 0)
result1 ^= a[i];
else
result2 ^= a[i];
}

if(result1 < result2)
printf("%d %d\n", result1, result2);
else
printf("%d %d\n", result2, result1);


delete[] a;
a=NULL;
}
return 1;

}