-
题意:有一个长度为\(n\)的数组,从第一天开始,第\(i\)天可以使\(i\)位置上的数\(+1\),当\(i=n\)时,下次从\(i=1\)再开始,另外,在每天结束时,你可以使任意一个位置上的数\(+1\;or\;-1\),或者不变,求最少经过多少天可以使得每个位置上的数都相等.
-
题解:我们对天数进行二分,由中位数定理:
数列中所有数到中位数的距离最小
.我们写一个check函数来判断当前天数是否满足条件,\(round\)表示轮数,\(rest\)表示剩下的天数,然后我们记录一个新的\(b\)数组表示所有天数操作完后的值,取中位数为基准,记\(res\)为每天结束后操作的总次数,如果\(res<=x\),则当前的天数满足条件,然后不断二分找一个最小的满足条件的天数即可. -
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <stack> #include <queue> #include <vector> #include <map> #include <set> #include <unordered_set> #include <unordered_map> #define ll long long #define fi first #define se second #define pb push_back #define me memset const int N = 1e6 + 10; const int mod = 1e9 + 7; using namespace std; typedef pair<int,int> PII; typedef pair<long,long> PLL; int n; ll a[N],b[N]; bool check(ll x){ int round=x/n; int rest=x%n; for(int i=1;i<=n;++i){ b[i]=a[i]+round; if(rest){ b[i]++; rest--; } } sort(b+1,b+1+n); ll res=0; for(int i=1;i<=n;++i){ res+=abs(b[i]-b[n/2+1]); } return res<=x; } int main() { ios::sync_with_stdio(false); 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; } printf("%lld\n",l); return 0; }