poj3484详解(二分)

(一道思路不错的二分,但是这题比较难看懂,并且输入有点恶心!)

题目大概意思为每个数据给你 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));
        }
    }
}
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值