HDU6383(二分最大最小数)

题意

给一个n个数的数列,给一个操作:对于任意两个数a,b(下标不同即可),一个数减2,另一个数加1. 给一个好的序列的定义:如果这个数列最大的数和最小的数相差<=1且每个数都大于0。经过若干次操作后,将这个数列变成好数列,问在所有的情况中,最小数的最大值是多少。

分析

最小数的最大值= =,显然的二分法,当时竟然没有一脸就反应过来,贼难受。

解法是枚举这个最小数,设其为x,x最小是0,最大设为开始这个数列的最大值就行了。我开始设置的平均值,这样并不对(暂时还没想明白)。然后check函数是重点,一开始没想清楚- -白花了很多时间。

按照题意是说两个可以换一个,枚举的时候我取的数列的最小值x已经确定了,对于那些小于当前x的值,肯定是要多的2个来补的。那我们可以遍历整个数组,看看有多少个需要补的,然后再看多了多少个可以填上去。这里有两个问题,下面一个一个分析。第一个问题是为什么他是单调的,也就是为什么可以二分。因为,x如果很大的话,导致每个都需要其他的来补,肯定不行,那x很小的话,导致每个都多了,那我们可以任取多的两个加到其他的,就减少了一个,这样多的一定可以变少,那最后如果每个只多了一个1怎么办?多的一个1肯定是不能加的,但是题意说整个数列最小的数,而且极差不超过1,显然也是好数列。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 3e5 + 5;
ll p[maxn];
int n;
bool check(ll x)
{
    ll zheng = 0, fu = 0;
    for (int i = 0; i<n; i++)
    {
        if ((p[i] - x)>0) zheng += ((p[i] - x) / 2);
        else if ((x - p[i])>0) fu += (x - p[i]);
    }
    if (zheng >= fu) return true;
    else return false;
}
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while (t--)
    {
        ll maxx=-1;
        cin >> n;
        for (int i = 0; i<n; i++)
        {
            cin >> p[i];
            maxx =max(p[i],maxx);
        }
        ll l = 0, r = maxx, ans = 0;
        while (r>l)
        {
            ll mid = (r + l) >> 1;
            if (check(mid)) l = mid+1;
            else r = mid-1;
        }
        if (check(l)) cout << l << endl;
        else cout << l-1 << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值