FZU Problem 1723 我就不信你能找得到

Problem 1723 我就不信你能找得到

Accept: 487 Submit: 2230 Time Limit: 1000 mSec Memory Limit : 32768 KB

img Problem Description

yayamao是只很笨的猫。它只认识偶数,它认为成双成对才是完美的。所以对于yayamao来说偶数是可数的,奇数是不可数的。

另外,yayamao它总是想写乱七八糟的问题,可是自己又很笨,不会做。这不,这只傻猫又出了道乱七八糟的题目,只能请教你们来做做喽。

yayamao面前有N个食物,每一个食物都有一种代号V。现在yayamao要开始整理这么多吃的东东了,就是说yayamao想要统计同一种食物一共有多少个。

同时yayamao被告知这N个食物中仅有两种食物是不可数的。yayamao的目的很简单,能不能帮他找出这两种不可数的食物?

很简单吧?是不是认为yayamao很笨啊?这么简单都不会,还等什么呢?

Kill it in seconds…

img Input

第一行一个T(1<=T<=10),代表有T组测试数据。

每组数据的第一行是一个N(N<=10^6),代表yayamao面前有N个食物。

接下来的一行有N个整数,第i个整数代表第i个食物的种类代号Vi

img Output

每组数据输出两个数A和B,A<B, 表示A,B两种食物是不可数的。A,B中间隔一个空格,行末要换行。

img Sample Input

2
10
1 1 1 2 2 2 3 3 4 4
20
0 1 0 1 2 3 4 2 3 4 65535 65535 65535 789456123 789456123 789456123 10 10 10 10

img Sample Output

1 2
65535 789456123

img Source

FZU 2009 Summer Training Qualification – Hero Revival 2

解决方案

有一种运算叫做异或,两个数的异或是这两个数的二进制的差的绝对值。

交换两个整数的值而不必用第三个参数,比如
a = 9;
b = 11;

a=a^b; 1001^1011=0010
b=b^a; 1011^0010=1001
a=a^b; 0010^1001=1011

a = 11;
b = 9;

这里就是这个的一个运用。

因为两个相同的数异或之后为0,所以只要把所有输入的数进行异或操作,则只剩下两个为奇数次数的数的异或,再运用上面的方法把他们取出来就OK。

#include<stdio.h>
#include<algorithm>
using namespace std;
__int64 a[1000002];
int main()
{
	__int64 m, n, i, j, s, k, t;
	scanf("%I64d", &t);
	while (t--)
	{
		scanf("%I64d", &n);
		s = 0;
		for (i = 0; i < n; i++) {
			scanf("%I64d", &a[i]);
			s ^= a[i];
		}
		//此时的s是两个为奇数次数的数的异或
		//接下来要将s与两个奇数次数的数其中之一进行一次异或,便可以得到其中一个奇数
		//又因为s的二进制中第i位如果为1则这两个奇次的数的第i位必然一个为1另一个为0
		//所以遍历所有输入的第i位为1的所有数都与s进行异或,便可以得到其中一个奇数次的数
        //再异或一次,便可得到另一个奇数次的数
		m = s, k = s, j = 0;
		//找到m二进制右数第一位1
		while (m) {
			j++;
			if (m % 2 == 1) break;
			m /= 2;
		}
		j--;
		for (i = 0; i < n; i++)
			if (a[i] >> j & 1)
				s ^= a[i];
		k ^= s;
		printf("%I64d %I64d\n", min(k, s), max(k, s));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值