HDU 6383 p1m2 (2018 “百度之星”程序设计大赛 - 初赛(B))(二分答案)

p1m2

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 736    Accepted Submission(s): 268


 

Problem Description

度度熊很喜欢数组!!

我们称一个整数数组为稳定的,若且唯若其同时符合以下两个条件:

1. 数组里面的元素都是非负整数。
2. 数组里面最大的元素跟最小的元素的差值不超过 1。

举例而言,[1,2,1,2] 是稳定的,而 [−1,0,−1] 跟 [1,2,3] 都不是。

现在,定义一个在整数数组进行的操作:

* 选择数组中两个不同的元素 a 以及 b,将 a 减去 2,以及将 b 加上 1。

举例而言,[1,2,3] 经过一次操作后,有可能变为 [−1,2,4] 或 [2,2,1]。

现在给定一个整数数组,在任意进行操作后,请问在所有可能达到的稳定数组中,拥有最大的『数组中的最小值』的那些数组,此值是多少呢?

 

Input

输入的第一行有一个正整数 T,代表接下来有几组测试数据。

对于每组测试数据:
第一行有一个正整数 N。
接下来的一行有 N 个非负整数 xi,代表给定的数组。

* 1≤N≤3×105
* 0≤xi≤108
* 1≤T≤18
* 至多 1 组测试数据中的 N>30000

Output

对于每一组测试数据,请依序各自在一行内输出一个整数,代表可能到达的平衡状态中最大的『数组中的最小值』,如果无法达成平衡状态,则输出 −1。

Sample Input

 

2

3

1 2 4

2

0 100000000

 

Sample Output

 

2

33333333

Source

2018 “百度之星”程序设计大赛 - 初赛(B)

题意:

给你一个序列a,定义一种稳定状态,一个序列最小值与最大值的差值<=1,且序列中所有元素>=0则说这个序列使稳定的。

现在有一种操作,取一个序列不同位置的两个数a,b,将a+1,b-2,再放回原来的位置

问你给你一个序列,所能到达的稳定状态中,最小值最大是多少,不存在输出-1

解析:

这道题在做的时候,听了大佬的思路,二分答案,但也写了半天,二分的check写的也不是很好,所以决定重新补一遍。

官方题解里面都是一些证明,证明这个题目中隐藏的很多结论,譬如说,这个题目不可能输出-1,

对于任意一个二分出来的答案V,一定存在且 \min(A) \le V。。。。。。。

这里其实很多结论都是可以猜出来的...

言归正传,二分答案关键是如何验证答案,这里验证的方法

1.对于a[i]>v的元素,我们一定是减少的,减少的次数就是sum1+=(a[i]-v)/2

2.对于a[i]<=v的元素,我们会让他去增加到v,所以增加的次数就是sum2+=v-a[i]

那么如果sum1>=sum2,则说明这个序列的最小值还有待提高,因为还有减少的次数没有用完

否则,说明这个序列的最小值太高了。

用v=5  a=3 10 12 14 15 17,最后一定能化成a[min]=5的最小序列

因为当a[i]=6, a[j]=15,你可以先让a[i]-2,a[j]+1,a[i]=4,a[j]=16,然后进行两次操作,a[i]=6,a[j]=12,这样一直做下去一定可以使a[j]=5或者6

#include <cstdio>
#include <cstring>
#include <set>
#define Max(a,b) a>=b?a:b
#define Min(a,b) a<=b?a:b
using namespace std;
const int MAXN = 3e5+10;
typedef long long ll;
const int INF = 0x3f3f3f3f;

ll a[MAXN];
int n;
ll summ=0;
ll check(ll x)
{
    ll sum1,sum2;
    sum1=sum2=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>x)
        {
            sum1+=(a[i]-x)/2;
        }
        else
        {
            sum2+=(x-a[i]);
        }
    }
    if(sum1>=sum2) return true;
    else return false;
}


int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll ans=-1;
        scanf("%d",&n);
        ll maxx=0;
        ll minn=INF;
        summ=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d",&a[i]);
            summ+=a[i];
             maxx=Max(maxx,a[i]);
             minn=Min(minn,a[i]);
        }
        if(minn==maxx||minn==(maxx-1)) ans=minn;
        int l=0;
        int r=maxx;
        while(l<r)
        {
            ll mid=(l+r)>>1;
            int tmp=check(mid);
            if(tmp) ans=Max(ans,mid),l=mid+1;
            else r=mid;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/81625270