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

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

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

思路
那天晚上有事就没打。赛后补的。
很容易想到二分,答案肯定满足单调性的。
不过check那里刚开始我写挂了。。
下面黑体加粗部分是我写挂的错误理解

我错误的以为只需要把增长后的n个数求和一下sum,然后枚举这n个数,取min(abs(sum-n*a[i])) 即计算总和与最后一样高度的总和差值即可。
为什么是错误的?
比如
3
2 5 6
假设此时mid=4
那么容易得到增长后的高度为4 6 7
如果按照我那样的做法总和sum=4+6+7=17
那么枚举取得的最小操作次数为1,即3 * 6-17=1
这样只是计算总和与目标总和的差值(如果没要求高度一样,只要求总和一样,那我还二分啥?),但是目的是要求把所有水稻高度都变一样。所以这样是不行的 最小操作次数应该是3,4+2,7-1。

所以应该去枚举每个高度,计算1到i块的总和 与i * b[i]比较,计算i+1到n块的总和与 (n-i-1) * b[i]比较 注意这里要求有序。
所以应该把增长后的高度排序后,处理出来前缀和进行枚举即可。只要最小操作次数≤二分出来的答案,那么就下调二分上界。
而对于增加后的高度很好计算,就是计算x/n、x%n即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[1<<17],b[1<<17],c[1<<17];
ll n;
bool check(ll x){
    ll sum=0;
    ll k=x/n,r=x%n;
    for(int i=1;i<=n;i++){
        b[i]=a[i]+k+(i<=r);
    }
    sort(b+1,b+1+n);
    for(int i=1;i<=n;i++)  c[i]=c[i-1]+b[i];
    ll mi=1e18;
    for(int i=1;i<=n;i++){
        mi=min(mi,i*b[i]-c[i]+(c[n]-c[i])-(n-i)*b[i]);
    }
    return x>=mi;

}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    ll l=0,r=1e18,mid;
    while(l+1<r){
        mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid;
    }
    cout<<r<<endl;
    return 0;
}