牛客5531C-牛牛的揠苗助长-二分+中位数

链接:https://ac.nowcoder.com/acm/contest/5531/C?&headNav=acm
来源:牛客网

题目描述:

牛牛有一块长度大小为n的菜园,他首先对这块菜园从1到n进行了编号,每一块地分别为1号、2号…n号菜地,然后他往每块菜地中都种下了一些水稻,一开始,第i块菜地中的水稻高度均为a[i]个单位。然后我们知道水稻的生长周期都是n天,也就是说每逢n天水稻就会长高一个单位。但是不巧的是整个菜园中每一块菜地的生长周期都错开了,具体来说,第1天的时候第1块菜地中的水稻长高一个单位,第2天的时候第2块菜地中的水稻长高一个单位…第n天的时候第n块菜地中的水稻长高一个单位,接下来第n+1天,又轮到第1块菜地中的水稻长高一个单位以此类推。

每天在水稻进行自然生长之后,牛牛可以施展他神奇的魔法,这个魔法可以让任意一块菜地中的水稻长高一个单位,或者让任意一块菜地中的水稻缩短一个单位,当然啦,他也可以不进行任何操作。

牛牛看到菜园中的水稻参差不齐十分难受,请问至少在第几天,他能够让所有的水稻都长到同一个高度?

输入描述:

第一行是一个正整数n(1≤n≤105 ),表示有菜园有n块菜地。
接下来一行输入n个正整数,表示每块菜地上水稻的高度,水稻的高度1≤a[i]≤109
保证一开始输入时水稻的高度不全都相同(数据保证答案至少为1)。

输出描述:

输出一个正整数表示问题的答案。

输入样例:

3
1 2 3

输出样例:

1

核心思想:

在long long范围内二分答案x。
对于x,令y=x%n。因为自动生长,前y块地的高度+1。(倍数部分都+1,相当于不变)
现在还需要考虑x次的魔法。要让使用的魔法次数尽可能的少,就要让所有水稻的高度向中位数靠近。遍历模拟靠近的过程,累计使用魔法的次数,如果次数<=x,则x满足条件。

复杂度:二分logn*(查找中位数n*logn+遍历模拟n)=(logn)2*n

代码如下:

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1e5+20;
ll n,a[N],b[N];//原数据存在b数组中,a数组用于排序 
bool pd(ll x)
{
	ll y=x%n,te;
	//自动生长 
	for(int i=1;i<=y;i++)
		a[i]=b[i]+1;
	for(int i=y+1;i<=n;i++)
		a[i]=b[i];
	//查找中位数 
	sort(a+1,a+n+1);
	if(n&1)
		te=a[n/2+1];
	else
		te=(a[n/2]+a[n/2+1])*1.0/2+0.5;
	//使用魔法 
	ll z=0;
	for(int i=1;i<=n;i++)
	{
		z+=labs(a[i]-te);
		if(z>x)
			break;
	}
	if(z>x)
		return 0;
	else
		return 1;
}
ll fun()//二分答案 
{
	ll l=0,r=1e17,ans=0;
	while(l<=r)
	{
		ll mid=(l+r)>>1;
		if(pd(mid))
		{
			ans=mid;
			r=mid-1;
		}
		else
			l=mid+1;
	}
	return ans;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%lld",&b[i]);
	printf("%lld\n",fun());
	return 0;
}

你可能感兴趣的:(二分)