題目鏈接
思路:v.first表示元素的值,second表示元素出現的個數,num【i】代表【1,i-1】的元素的個數前綴和,sum1【i】代表【1,i-1】中元素的個數*值得前綴和,num2【i】和sum2【i】同理求得是【i+1,n】得前綴和,我們知道最終結果肯定是初始元素內得某個數變成了k個,那麼我們就枚舉假設把當前數變成k個,遍歷取min即可,那麼對於a【i】來說要把它變成k的操作就是,如果num1【i】+v.second大於等於k的話就計算一下左邊的貢獻,同理理算右邊的貢獻,同時不要忘了如果左右單個都不滿足的話要取中間的,也就是ans=min(ans,left+right+k-v[i].second)。,left和right的話分別表示把【1,i-1】的元素變成a【i-1】需要的操作和【i+1,n】的元素變成a【i+1】需要的操作。
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int maxn=2e5+1;
map<ll,ll>p;
vector<pair<ll,ll>>v;
ll k,sum1[maxn],sum2[maxn],num1[maxn],num2[maxn],a[maxn];
int main()
{
int n;
scanf("%d %lld",&n,&k);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]),p[a[i]]++;
for(auto it=p.begin();it!=p.end();it++)
v.push_back({it->first,it->second});
ll t=0,tt=0,ans=1e18;
for(int i=0;i<v.size();++i)
{
num1[i]=t;
sum1[i]=tt;
t+=v[i].second;
tt+=v[i].first*v[i].second;
}
t=tt=0;
for(int i=v.size()-1;i>=0;--i)
{
num2[i]=t;
sum2[i]=tt;
t+=v[i].second;
tt+=v[i].first*v[i].second;
}
for(int i=0;i<v.size();++i)
{
if(v[i].second>=k){
puts("0");return 0;
}
ll left=num1[i]*(v[i].first-1)-sum1[i],right=sum2[i]-num2[i]*(v[i].first+1);
if(v[i].second+num1[i]>=k) ans=min(ans,left+k-v[i].second);
if(v[i].second+num2[i]>=k) ans=min(ans,right+k-v[i].second);
ans=min(ans,left+right+k-v[i].second);
}
printf("%lld\n",ans);
}