(一道思路不错的二分,但是这题比较难看懂,并且输入有点恶心!)
题目大概意思为每个数据给你 n 组数,问这 n 组数中哪个数出现的次数为奇数(保证只有一个数)
每组数给的方式为 X , Y , Z
这组数即为 X , X + Z , X + 2 * Z , X + 3 * Z , … , X + K * Z , …(当 ( X + K * Z ) <= Y 时)
输入就不说了,到时候看代码
这道题我们这么考虑,因为除了所求的数 n ,其他所有数出现的次数都为偶数
那么 n + m 与 其之后的数出现的次数和,即为 偶数 + 偶数 + … + 偶数 = 偶数
那么 n 与 其之后的数出现的次数和,即为 奇数 + 偶数 + 偶数 + … + 偶数 = 奇数
那么 n - m 与其之后的数出现的次数和,即为 偶数 + … + 偶数 + 奇数 + 偶数 + … + 偶数 = 奇数
这么一看是不是就是最大化最小值的思路,找最大的数,使次数和为奇数,直接二分开始
代码如下:
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
typedef long long ll;
ll x[100005], y[100005], z[100005];
void trans(string str, int num)
{
x[num] = 0; y[num] = 0; z[num] = 0;
int i = 0;
while(str[i] <= '9' && str[i] >= '0')
{
x[num] = x[num] * 10 + str[i] - '0';
i++;
}
i++;
while(str[i] <= '9' && str[i] >= '0')
{
y[num] = y[num] * 10 + str[i] - '0';
i++;
}
i++;
while(str[i] <= '9' && str[i] >= '0')
{
z[num] = z[num] * 10 + str[i] - '0';
i++;
}
}
ll deal(ll n, int k)
{
ll m = 0, mm = 0;
for(int i = 0; i < k; i++)
{
ll sum = (y[i] - x[i]) / z[i] + 1;
if(x[i] > n)
{
mm += sum;
}
else if(y[i] < n)
{
continue;
}
else
{
if((n - x[i]) % z[i] == 0)
{
mm += sum - (n - x[i]) / z[i];
m++;
}
else
{
mm += sum - (n - x[i]) / z[i] - 1;
}
}
}
if(mm % 2 == 1)
{
return m;
}
else
{
return -1;
}
}
int main()
{
string str;
while(getline(cin, str))
{
if(str == "") continue;
int num = 0;
trans(str, num++);
while(getline(cin, str))
{
if(str == "") break;
trans(str, num++);
}
ll l = 0, r = (1LL << 32), mid = (l + r) / 2;
while(l < r - 1)
{
if(deal(mid, num) != -1)
{
l = mid;
mid = (l + r) / 2;
}
else
{
r = mid;
mid = (l + r) / 2;
}
}
if(l == 0)
{
printf("no corruption\n");
}
else
{
printf("%lld %lld\n", l, deal(l, num));
}
}
}