/*
快速找出机器故障:
为了保证搜索引擎的服务质量,我们需要保证每份数据都有多个备份
假设一个机器仅存储了一个标号为ID的记录(假设ID是小于10亿的整数),假设每份数据保存了两个备份,这样
就有两个机器储存了同样的数据。
1在某个时间,如果得到一个数据文件ID的列表,是否能够快速地找出这个表中仅出现一次的ID?
2如果已经知道只有一台机器死机(也就是说只有一个备份都是)呢?如果有两台机器死机呢(假设同一个数据
的两个备份不会同时丢失)?
3如果丢失的两台机器ID相同呢?
分析:
这个问题可以转化成:有很多的ID,其中只有一个ID出现的次数小于2,其他正常ID出现的次数都等于2,如何找到
这个次数为1的ID。
这样就转化成剑指上面的:所有元素全部异或,最终剩下的数就是那个数
第二问转化为这群数中有两个数各出现一次,其余出现0次,所以也是剑指上的题目,需要全部异或得到数字
x,然后获取x的比特表示中最右边的1,记为该位为第n位,根据比特表示中的第n位是否为1,将数组划分
成两部分,每一部分中在分别全部异或一遍,即可。
局限:只能解决两台故障机器ID不同的情况。如果ID相同,则无法解决
第三问:
预先计算并保存好所有ID的求和(不变量),顺序列举当前所有剩下的ID,对它们求和,然后用总值 – 剩余值 = 死机
的机器ID值。由于总和可以先计算好,算法的时间复杂度为O(N),空间复杂度为O(1)
当两个ID不同时:总和 – 剩余和 = x + y
当两个ID相同时:这个时候,x = (总和-剩余和)/2
这个时候可以构造二元一次方程组来做,比如:总乘积/剩余乘积 = x*y(或者求出x*x + y*y = b)
联立解方程
{x + y = a
{x * y = b
此方法的缺陷是:需要事先知道原来n个数,如果题目只给你丢失的数,那就坑爹了
样例输入:
8
2 4 3 6 3 2 5 5
2 4 3 6 3 2 5 5 4 6
样例输出:
4 6
*/
#include <stdio.h>
#include <math.h>
const int MAXSIZE = 10000;
void process()
{
int n;
while(EOF != scanf("%d",&n))
{
if(n < 0)
{
break;
}
int iRemainArr[MAXSIZE];
long long lRemainSum = 0,lRemainMul = 1,lIntactSum = 0,lIntactMul = 1;
for(int i = 0 ; i < n ; i++)
{
scanf("%d",&iRemainArr[i]);
lRemainSum += iRemainArr[i];
lRemainMul *= iRemainArr[i];
}
int iIntactArr[MAXSIZE];
for(int j = 0 ; j < n + 2 ; j++)
{
scanf("%d",&iIntactArr[j]);
lIntactSum += iIntactArr[j];
lIntactMul *= iIntactArr[j];
}
long long lSum = lIntactSum - lRemainSum;
long long lMul = lIntactMul/lRemainMul;
long long lSqrt = (long long)sqrt(double(lSum*lSum - 4*lMul) + 0.5);
long long lX = (long long)((lSum - lSqrt)/2);
long long lY = (long long)((lSum + lSqrt)/2);
printf("%lld %lld\n",lX,lY);
}
}
int main(int argc,char* argv[])
{
process();
getchar();
return 0;
}