Make k Equal CodeForces - 1328F(贪心+思维)

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.

Examples
Input
6 5
1 2 2 4 2 3
Output
3
Input
7 5
3 3 2 1 1 1 3
Output
4
题意:
给一个 n 和 k ,以及长度为 n 的序列 a 。

有两种操作:

让数组中其中一个最小值的值加一。
让数组中其中一个最大值的值减一。
问:最少几次操作,可以使得数组中至少有 k 个数相等。

思路:贪心可得,最后的相等的k个数肯定是初始数组中的某个数字。假设我们让某一个数x作为这最终的答案,那么在它之前的比它小的数,都要变成x-1,才可以执行题目要求的这一操作。比它大的数同理。
num[i]代表的是第i个数,cnt[i]代表的是num[i]的个数。
lcnt[i]代表的是比num[i]小的数的个数,lsum[i]代表的是将 小于num[i]的数变为num[i]-1 所花费的代价。
rcnt[i]代表的是比num[i]大的数的个数, rsum[i]代表的是将 大于num[i]的数变为num[i]+1 所花费的代价。
如果某一个数的个数本来就大于等于k的话,直接输出0就可以了。否则它就可以从小于它或者大于它的某些数转化而来。
在这里插入图片描述
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define inf 1e18
using namespace std;

const int maxx=2e5+100;
int cnt[maxx],num[maxx],a[maxx];
ll lcnt[maxx],lsum[maxx],rcnt[maxx],rsum[maxx];
int n,k;

int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	int m=0,sum=0;
	a[n+1]=0;
	for(int i=1;i<=n;i++)
	{
		sum++;
		if(a[i]!=a[i+1])
		{
			num[++m]=a[i];
			cnt[m]=sum;
			sum=0;
		}
	}
	lcnt[1]=lsum[1]=0;
	for(int i=2;i<=m;i++)
	{
		lsum[i]=lsum[i-1]+(ll)cnt[i-1]*(ll)(num[i]-1-num[i-1])+(ll)lcnt[i-1]*(ll)(num[i]-num[i-1]);
		lcnt[i]=lcnt[i-1]+cnt[i-1];
	}
	//lsum[i-1]代表的是变为num[i-1]-1所需要的代价。
	//cnt[i-1]*(num[i]-1-num[i-1])代表的是将num[i-1]变为num[i]-1所需要的代价。
	//lcnt[i-1]*(num[i]-num[i-1])代表的是将num[i-1]-1变为num[i]-1所需要的代价。
	rcnt[m]=rsum[m]=0;
	for(int i=m-1;i>=1;i--)
	{
		rsum[i]=rsum[i+1]+(ll)cnt[i+1]*(ll)(num[i+1]-num[i]-1)+(ll)rcnt[i+1]*(ll)(num[i+1]-num[i]);
		rcnt[i]=rcnt[i+1]+cnt[i+1];
	}//同理。
	ll ans=inf;
	for(int i=1;i<=m;i++)
	{
		if(cnt[i]>=k) ans=0;
		else 
		{
			int res=k-cnt[i];
			//三个方面有可能转化,因此要取最小值。
			if(i>1&&i<m) ans=min(ans,res+rsum[i]+lsum[i]);
			if(i>=1&&rcnt[i]>=res) ans=min(ans,res+rsum[i]);
			if(i<=m&&lcnt[i]>=res) ans=min(ans,res+lsum[i]);
		}
	}
	cout<<ans<<endl;
	return 0;
}

努力加油a啊,(o)/~

发布了596 篇原创文章 · 获赞 47 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/starlet_kiss/article/details/105176165