何老板有一个长度为NNN的整数数列AAA。
他让你任选一个整数xxx,使得下面式子的值最小:
∣A1−(X+1)∣+∣A2−(X+2)∣+∣A3−(X+3)∣+......+∣AN−(X+N)∣|A_1-(X+1)|+|A_2-(X+2)|+|A_3-(X+3)|+......+|A_N-(X+N)|∣A1−(X+1)∣+∣A2−(X+2)∣+∣A3−(X+3)∣+......+∣AN−(X+N)∣
请你计算出上面式子的最小值。
分析
这道题不算太难,但要提前知道一个知识点:
对于形如∣a1−y∣+∣a2−y∣+......+∣an−y∣|a_1-y|+|a_2-y|+......+|a_n-y|∣a1−y∣+∣a2−y∣+......+∣an−y∣式子,当其为最小值时,yyy当且仅当为序列aaa的中位数
那我们只需要对上式拆开括号就可以变成这种形式:∣Ai−(X+i)∣=∣(Ai−i)−X∣|A_i-(X+i)|=|(A_i-i)-X|∣Ai−(X+i)∣=∣(Ai−i)−X∣其中Ai−iA_i-iAi−i是个定值,可以被提前求出;
现在就好办了,我们只需要把AiA_iAi预处理成Ai−iA_i-iAi−i,然后求出新序列的中位数即是XXX的值,最后带入求解即可;
时间复杂度O(NlogN)O(N\log N)O(NlogN),可以通过(求中位数时要排序!)
Code
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define int long long
using namespace std;
int n,a[200005],ans,num;
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){scanf("%lld",&a[i]);a[i]-=i;}
sort(a+1,a+n+1);
if(n&1){num=a[n/2+1];}
else{num=(a[n/2]+a[n/2+1])/2;}
for(int i=1;i<=n;i++){ans+=abs(a[i]-num);}
printf("%lld",ans);
return 0;
}