一、题目翻译
如果没有发现细微的形式,那么对大量数据集合进行数据挖掘是一件痛苦而又长时间的过程。
一家公司的某个软件成对的使用组件生成了大量的数据对象,因为是成对使用,所以每个数据对象出现的次数一定为偶数次,但是在多次巧合的影响下,某些情况出现了问题,确定有且仅有一个数据对象出现了奇数次,请您编写一个程序,找出这个出现了奇数次的元素。
题目包含多组测试用例,用一行或者多行空行来分割,每个数列的表现形式为 x y z,数列的元素为 x,x+2*z,x+3*z...x+k*z,满足(x+k*z)<=y
输出,如果没有数据对象出现了奇数次,输出no corruption,如果有,输出这个数字,和这个数字出现的次数(题目确保最多只有一个数据对象出现了奇数次)
二、解题思路
假设所有的数列都不包含某个数字出现了奇数次,那么 给定任意一个R,所有数列的小于等于R的元素出现的次数求和一定是一个偶数。
如果其中有且仅有一个元素P出现了奇数次,其他的元素都出现了偶数次,那么当R小于P时,所有数列的小于等于R的元素出现的次数求和也一定是一个偶数;但是当R大于等于P时,所有数列的小于等于R的元素出现的次数求和也一定是一个奇数。
因为多个数字求和,其中如果都是偶数,那么结果也一定时偶数!但是如果一堆偶数中出现一个奇数,那么最终的和也一定为奇数!
所以本题目就可以去二分这个R,一定有当R大于等于P时,不管R为多大,所有数列小于等于R的元素出现次数和一定为奇数。当R小于P时,不管R为多小,所有数列小于等于R的元素出现次数和一定为偶数。
同时网上的题解说这个题目可以用fgets来获取输入,但是我当时不知道,使用的是最基础的scanf("%c,&c),一个字符一个字符的读入!
运行情况如下:
三、代码
一点点小建议!做算法题,除非迫不得已想不出来!否则不推荐去看别人的代码,能不能看懂是一方面,更重要的是比源码更重要的是能写出源码的逻辑和思维!
#include <iostream>
using namespace std;
typedef long long ll;
struct Node
{
ll x, y, z;
Node(ll x = 0, ll y = 0, ll z = 0) : x(x), y(y), z(z) {}
};
char charArray[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
Node nodes[1000007];
int N;
ll max(ll a, ll b)
{
if (a > b)
{
return a;
}
else
{
return b;
}
}
ll min(ll a, ll b)
{
if (a < b)
{
return a;
}
else
{
return b;
}
}
bool isNumber(char c)
{
for (int i = 0; i < 10; i++)
{
if (c == charArray[i])
{
return true;
}
}
return false;
}
bool isBlank(char c)
{
return c == ' ';
}
bool judge(ll mid)
{
int count = 0;
for (int i = 1; i <= N; i++)
{
// 要求mid小于x,并且x<=y
if (mid < nodes[i].x || nodes[i].y < nodes[i].x)
{
continue;
}
int len = 0;
if (mid < nodes[i].y)
{
len = mid - nodes[i].x;
}
else
{
len = nodes[i].y - nodes[i].x;
}
len = len / nodes[i].z;
len++;
count += (len % 2);
}
return count % 2 == 0;
}
ll calcCount(ll num)
{
ll count = 0;
for (int i = 1; i <= N; i++)
{
if (num < nodes[i].x || nodes[i].y < nodes[i].x || num > nodes[i].y)
{
continue;
}
if ((num - nodes[i].x) % nodes[i].z == 0)
{
count++;
}
}
return count;
}
void binarySearch(ll mint, ll maxt)
{
ll left = mint - 1;
ll right = maxt + 1;
while (left + 1 < right)
{
ll mid = (left + right) / 2;
if (judge(mid))
{
left = mid;
}
else
{
right = mid;
}
}
if (left == maxt)
{
printf("no corruption\n");
}
else
{
printf("%lld %lld\n", right, calcCount(right));
}
}
void flush()
{
for (int i = 1; i <= N + 1; i++)
{
nodes[i].x = 0;
nodes[i].y = 0;
nodes[i].z = 0;
}
}
void solve()
{
// test
int mint = nodes[1].x, maxt = nodes[1].y;
for (int i = 1; i <= N; i++)
{
mint = min(nodes[i].x, mint);
maxt = max(nodes[i].y, maxt);
}
binarySearch(mint, maxt);
}
int main()
{
char c;
N = 1;
bool isOK = false;
int mode = 1;
int nextLineCount = 0;
while (~scanf("%c", &c))
{
if (isNumber(c))
{
nextLineCount = 0;
switch (mode)
{
case 1:
nodes[N].x = nodes[N].x * 10 + (c - '0');
break;
case 2:
nodes[N].y = nodes[N].y * 10 + (c - '0');
break;
case 3:
nodes[N].z = nodes[N].z * 10 + (c - '0');
break;
default:
break;
}
}
else if (isBlank(c))
{
mode++;
}
else if (c == '\n')
{
if (nextLineCount == 0)
{
N++;
mode = 1;
}
nextLineCount++;
}
if (nextLineCount > 1 && N > 1)
{
N--;
solve();
flush();
N = 1;
}
}
if (nodes[1].x != 0)
{
if (nodes[N].x == 0)
{
N--;
}
solve();
}
return 0;
}