F. Make k Equal (思维)

题目大意:一个数组含有n个元素,没次操作只能使最大的减一或者最小的加一,设最终有k个相等的元素,问最少需要操作几次。

题解:注意每次只能使最大的减一或者最大的加一,设数组元素 1,2,5  ,假设我们要将前两个变成5,该怎么操作呢?1=>2,   2=>3,   2=>3,  3=>4,  3=>4  4=>5  4=>5,也就是我们每加一次或者减一次,都会使数字中的最大值或者最小值改变。假设数组长度为n,和为sum,至少出现x个t,那么操作次数为sum-x*t,这里是将n个元素全部变为t,我们只需要x个,多操作了n-x次,所以总的操作次数为sum-x*t-(n-x)。那这个题该怎么做呢?首先排序一下,然后预处理处前缀和与后缀和,然后枚举每个数(设为x)其出现的区间为[l,r],所以我们可以将[1,l-1]内的数变成x,也可以将[r+1,n]内的数变成x,如果数量上仍不满足的话,需要将两边都变成x。最后在减去多的就行了,具体实现都在code中

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=1e18+7;
const ll N=2e5+7;
ll arr[N];
ll dis[N],sum[N]; 
int main(){
    ll n,m;
    cin>>n>>m;
    for(ll i=1;i<=n;i++) cin>>arr[i];
    sort(arr+1,arr+1+n);
    for(ll i=1;i<=n;i++) dis[i]=dis[i-1]+arr[i];
    for(ll i=n;i>=1;i--) sum[i]=sum[i+1]+arr[i];
    ll ans=INF;
    ll l,r; 
    for(ll i=1;i<=n;i=r+1){
        r=l=i;
        while(arr[r]==arr[i]&&r<=n) r++;
        r--;
        if(r-l+1>=m){ 
            ans=0;
            break;
        }
        if(r>=m){
            ll num=(l-1)*arr[i]-dis[l-1];
            num-=r-m;
            ans=min(ans,num);
        }
        if(n-l+1>=m){
            ll num=sum[r+1]-(n-r)*arr[i];
            num-=(n-l+1-m);
            ans=min(ans,num);
        }
        if(r<m&&n-l+1<m){
            ll num=(l-1)*arr[i]-dis[l-1];//目前一共有r-1
            num+=sum[r+1]-(n-r)*(arr[i]);
            num-=(n-m);
            ans=min(ans,num);
        }
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Accepting/p/12851629.html