(贪心)codeforces 1328F&1355E

补了下**643—div.2**的题,发现**E**题挺有趣的与**1328E**类似,第一篇博客就用这个吧

先来1325F


题意挺简单的,用两个操作(1、最大数减1;2、最小数加1)把一组数里面的K个变成相同的数,一次只能操作一个数求最小的操作次数。
最开始想到了贪心但是贪歪了,于是进入了死胡同,最后是看了大佬的博客(https://www.cnblogs.com/dysyn1314/p/12579677.html)才恍然大悟,鄙人这篇博客就以大佬的博客为基础加一点自己的见解。
我们先来简化一下问题:用以上两个操作把一组有序的数(总个数为N)里面的K个数变成相同的数;
首先我们要清楚得出数的大小应该是原本数组中出现过的数,这不做过多解释。接下来我们设最后数值都为a原本的个数为n个
1:n>=k时,ans=0;
2:n<k时,我们需要把小于a的数变成(a-1),大于a的数变为(a+1),那为什么什么不是直接变为a呢,因为我们只需要K个就足够了,而(N-n)是有可能大于(K-n)的,
再让后在(a-1)和(a+)中取出(k-n)个即可;
再求一下前缀和(pre)和后缀和(suf),a第一次出现的位置(i)和最后一次出现的位置(j)我们就可以得出公式:(a-1)(i-1)-pre[i-1]+suf[i+1]-(a+1)(N-j)+(k-(j-i+1));
其实有时只需操作一边即可,大神们可以自己补充一下。
我们再把问题还原,发现我们只需要把数据变成有序的即可。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
int a[200002],N,K;
ll pre[200002],suf[200002],sum;
const ll INF=1e18;
int main(){
	cin>>N>>K; sum=0;
	for(int i=1;i<=N;i++) cin>>a[i];
	sort(a+1,a+N+1);
	for(int i=1;i<=N;i++){
		pre[i]+=pre[i-1]+a[i];
		suf[N-i+1]+=suf[N-i+2]+a[N-i+1];
	}
    ll ans=INF;
	{
		for(int i=1;i<=N;i++){
			int j=i;
			while(j+1<=N&&a[j+1]==a[i]) j++;
			if(j-i+1>=K){ans=0;break;}
			ll an1,an2,an,na;
			an1=(ll)(a[i]-1)*(i-1)-pre[i-1]; an2=suf[j+1]-(ll)(a[i]+1)*(N-j);
			an=an1+an2+(K-(j-i+1));
			ans=min(an,ans);
			if(j>=K) an=an1+(K-(j-i+1)),ans=min(an,ans);
			if((N-i+1)>=K)     an=an2+(K-(j-i+1)),ans=min(an,ans);
			i=j;
		}
	}
    cout<<ans<<endl;
return 0;
}

接下来看1355E

题意大致相同,不再对K做限制,操作也发生了改变(1、增加1个单位需要花费 A ;2、减少一个单位需要花费 R ;3、交换一个单位需要花费 M ;)
但是由于交换这一操作哦,可能产生不属于原本数据中的数,但这一点我们只需要另外计算即可,贴出代码,大家可以对比着理解一下

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
int a[100002],A,R,M,N;
ll pre[100002],suf[100002],sum;
const ll INF=1e18;
int main(){
	cin>>N>>A>>R>>M; sum=0;
	for(int i=1;i<=N;i++) cin>>a[i],sum+=a[i];
	sort(a+1,a+N+1);
	ll na,nb,aa=0,ar=0;
	na=sum%N,nb=sum/N;
	for(int i=1;i<=N;i++){
		pre[i]+=pre[i-1]+a[i];
		suf[N-i+1]+=suf[N-i+2]+a[N-i+1];
		if(a[i]>nb){
			aa+=(a[i]-nb);
			if(na&&a[i]>(nb+1)) ar+=(a[i]-nb-1);
		}
	}
    ll ans=INF;
    {//平均 
    	ll asn=INF,asb=INF;
		if(A+R>M){
			asn=M*(aa-na)+R*na;
		    if(na!=0)	asb=M*ar+A*(N-na);
		}
		else{
			asn=(A+R)*(aa-na)+R*na;
			if(na!=0)   asb=(A+R)*ar+A*(N-na);
		}
		ans=min(min(asn,asb),ans);
	}
	{//常规操作 
		for(int i=1;i<=N;i++){
			int j=i;
			while(j+1<=N&&a[j+1]==a[i]) j++;
			ll an1,an2,an,na;
			an1=(ll)a[i]*(i-1)-pre[i-1]; an2=suf[j+1]-(ll)a[i]*(N-j);
			an=A*an1+R*an2;
			if(an1<an2) na=M*an1+R*(an2-an1);
			else        na=M*an2+A*(an1-an2);
			ans=min(min(an,na),ans);
			i=j;
		}
	}
    cout<<ans<<endl;
return 0;
}
posted @ 2020-05-20 12:53  kidfff  阅读(93)  评论(0)    收藏  举报