Description
You are given the array a consisting of n elements and the integer k≤n.
You want to obtain at least k equal elements in the array a. In one move, you can make one of the following two operations:
Take one of the minimum elements of the array and increase its value by one (more formally, if the minimum value of a is mn then you choose such index i that ai=mn and set ai:=ai+1);
take one of the maximum elements of the array and decrease its value by one (more formally, if the maximum value of a is mx then you choose such index i that ai=mx and set ai:=ai−1).
Your task is to calculate the minimum number of moves required to obtain at least k equal elements in the array.
Input
The first line of the input contains two integers n and k (1≤k≤n≤2⋅105) — the number of elements in a and the required number of equal elements.
The second line of the input contains n integers a1,a2,…,an (1≤ai≤109), where ai is the i-th element of a.
Output
Print one integer — the minimum number of moves required to obtain at least k equal elements in the array.
题目大意
有n个数字,可以进行两种操作,将最大的减1,将最小的加1.需要获得k个相等的数字,输出最少需要的操作数
思路
先排序,维护前缀pre和后缀suf
枚举每一个可能的数字x,有四种可能的情况
1.原本的数量就大于等于k(ans=0)
2.将左边小的加成x
3.将右边大的减成x
4.左边小的加成x,右边大的减成x(这种情况只存在于单操作左或者右都不够k的时候(不然只操作一边更优))
具体的:
变量数组,得到某一数字x的最前和最后下标 l,r 区间[l,r]都是数字x
对于将左边全部加成x的操作数为a[l]×l-pre[l]
当然可能前面的数字挺多的,大于k了那就反悔,将多出来的退一步(减一,不能减更多了)。
右边同理:suf[r]-(n-r+1)×a[r];
两边:左边+右边…
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+5;
const ll inf=0x3f3f3f3f3f3f3f;
ll a[maxn],pre[maxn],suf[maxn];
int main()
{
int n,k;
scanf("%d %d",&n,&k);
for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
sort(a+1,a+n+1);
for(int i=1;i<=n;++i)pre[i]=pre[i-1]+a[i];
for(int i=n;i>=1;--i)suf[i]=suf[i+1]+a[i];
ll ans=inf,num;
for(int i=1;i<=n;++i){
int l=i,r=i;
while(r<n&&a[r]==a[r+1])++r;
i=r;
if(r-l+1>=k){
ans=0;
break;
}
if(r>=k){//左边够
num=l*a[l]-pre[l];//l左边移动到l
num=num-(r-k);//多余的移动反悔
ans=min(ans,num);
}
if(n-l+1>=k){//右边够
num=suf[r]-(n-r+1)*a[r];
num=num-((n-l+1)-k);//多余的移动反悔
ans=min(ans,num);
}
if(r<k&&n-l+1<k){//需要两边
ll num1=l*a[l]-pre[l];//l左边移动到l
ll num2=suf[r]-(n-r+1)*a[r];
num=num1+num2-(n-k);
ans=min(ans,num);
}
}
printf("%lld\n",ans);
return 0;
}