链接: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<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
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;
}