題目描述
牛牛有一塊長度大小爲n的菜園,他首先對這塊菜園從1到n進行了編號,每一塊地分別爲1號、2號…n號菜地,然後他往每塊菜地中都種下了一些水稻,一開始,第i塊菜地中的水稻高度均爲a[i]個單位。然後我們知道水稻的生長週期都是n天,也就是說每逢n天水稻就會長高一個單位。但是不巧的是整個菜園中每一塊菜地的生長週期都錯開了,具體來說,第1天的時候第1塊菜地中的水稻長高一個單位,第2天的時候第2塊菜地中的水稻長高一個單位…第n天的時候第n塊菜地中的水稻長高一個單位,接下來第n+1天,又輪到第1塊菜地中的水稻長高一個單位以此類推。
每天在水稻進行自然生長之後,牛牛可以施展他神奇的魔法,這個魔法可以讓任意一塊菜地中的水稻長高一個單位,或者讓任意一塊菜地中的水稻縮短一個單位,當然啦,他也可以不進行任何操作。
牛牛看到菜園中的水稻參差不齊十分難受,請問至少在第幾天,他能夠讓所有的水稻都長到同一個高度?
輸入描述:
第一行是一個正整數n (0-1e5)
表示有菜園有n塊菜地。
接下來一行輸入n個正整數,表示每塊菜地上水稻的高度
保證一開始輸入時水稻的高度不全都相同(數據保證答案至少爲1)。
輸出描述:
輸出一個正整數表示問題的答案。
示例1
輸入
3
1 2 3
輸出
1
說明
第一天,第一塊菜地的水稻高度增加1,牛牛使用他的魔法使得第三塊菜地的水稻再減少1。
此時三塊水稻的高度爲2 2 2.所有水稻的高度均相同。所以答案爲1天。
思路:很明顯的是對天數進行二分搜索,但是我們怎麼判斷給定的一個天數是不是可以讓其對齊呢,這裏我們先讓每一株水稻加上這n填循環的次數,假設我們此時判斷的是day天數時是不是滿足條件,那麼在這day天裏我們所有的水稻都要增長day/n 單位高度,然後前day%n 個水稻是要在這基礎上再增加1,然後這時候所有的水稻還是層次不齊的,但是我們還有day次操作,那因爲是參差不齊的,我們想讓水稻通過施魔法之後變得等高,當某一刻變成等高的時候,無論後面哪個長一個單位我們都可以用魔法讓它變成等高時候的高度,然後這裏有一個數學定理:數列各個數到中位數的距離和最小,就是說我們對所有的水稻施魔法,讓它變成最中間的那個水稻的高度,然後這樣總的施魔法次數就是最小的,然後我們一共可以施day次魔法,所以就那總的次數跟day作比較即可。拿官方題解的一個圖,更形象的說明一下!
AC代碼:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int a[maxn],temp[maxn],n;
ll check(ll day){
ll group=day/n;ll remain=day%n;
for(int i=1;i<=n;i++){
temp[i]=group+a[i];
if(remain){
temp[i]+=1;remain-=1;
}
}
sort(temp+1,temp+n+1);
ll sum=0;
for(int i=1;i<=n;i++){
sum+=abs(temp[i]-temp[n/2+1]);
}
return sum<=day;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
ll l=1,r=1e18;
while(l<r){
ll mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<l<<endl;
}
謝謝您訪問我的博客!