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
题意:
给你一个序列a,定义一种稳定状态,一个序列最小值与最大值的差值<=1,且序列中所有元素>=0则说这个序列使稳定的。
现在有一种操作,取一个序列不同位置的两个数a,b,将a+1,b-2,再放回原来的位置
问你给你一个序列,所能到达的稳定状态中,最小值最大是多少,不存在输出-1
解析:
这道题在做的时候,听了大佬的思路,二分答案,但也写了半天,二分的check写的也不是很好,所以决定重新补一遍。
官方题解里面都是一些证明,证明这个题目中隐藏的很多结论,譬如说,这个题目不可能输出-1,
对于任意一个二分出来的答案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;
}