本题是上一题的续篇,扩展篇。 同时也是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;
}