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