Codeforces Round #629 (Div. 3) F. Make k Equal(前綴和+思維)

題目鏈接
在這裏插入圖片描述
思路: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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章