Codeforces Round #629 (Div. 3) (A ~ F)

被强♂制♂上任的第一天

F. Make k Equal

题目-> http://codeforces.com/contest/1328/problem/F

题意:

给你 n 个数 , 通过任意次操作:

①最大数 - 1

②最小数 + 1

保证数组中有k个数相同 , 问最小操作次数

分析:

如果已经有k个相同的输出0,否则:

假设最终有k个a (首先明确这里的a 一定是输入数组的其中一个值 ,这样一定可以保证最优解), 那么对于任意数b ,

当b < a , 只有把所有小于a的数都变成a - 1 , 然后 再取其中的一个数 + 1 ,即可以得到一个a

当b > a ,只有把所有大于a的数都变成a + 1,然后 再取其中一个数 - 1, 即可以得到一个a

所以 , 先排序 ,接下来,枚举每个值是最优解的a , 然后a可以通过 比他小值 和 比他大的值 转移过来 , 从而求出解,详细看代码。

 

#include <bits/stdc++.h>
using namespace std;
const int maxn =  1e6 + 10;
#define ll long long
#define ios std::ios::sync_with_stdio(false)
const ll INF(0x3f3f3f3f3f3f3f3fll);
#define int long long
typedef unsigned long long ULL;

map<int , int>ma;
int a[maxn];
int b[maxn];///存不同的数
int c[maxn];///存每个不同数的个数
int pre[maxn] , pre_sum[maxn];///前缀个数,前缀和
int nex[maxn] , nex_sum[maxn];///后缀个数,后缀和
signed main()
{
    ios;
    cin.tie(0);///
    int n , k;
    cin >> n >> k;
    int cnt = 0;
    for(int i = 1 ; i <= n ; i ++){
        cin >> a[i];
        ma[a[i]] ++;
        cnt = max(cnt , ma[a[i]]);///记录最多的数的数量
    }
    if(cnt >= k)return cout << 0 << '\n' , 0;

    sort(a + 1 , a + 1 + n);
    cnt = 1;
    int sum = 1;
    for(int i = 1 ; i <= n ; i ++){
        if(a[i] == a[i + 1]) sum ++;
        else{
            b[cnt] = a[i];///记不同的数,这里用map记也可以
            c[cnt] = sum;///这个数有几个
            cnt ++ , sum = 1;
        }
    }
    n = cnt - 1;
    for(int i = 1 ; i <= n ; i ++)/// 前缀个数和前缀和
        pre[i] = pre[i - 1] + c[i] , pre_sum[i] = pre_sum[i - 1] + c[i] * b[i];
    for(int i = n ; i >= 1   ; i --) 
        nex[i] = nex[i + 1] + c[i] , nex_sum[i] = nex_sum[i + 1] + c[i] * b[i];
    int ans = INF;
    for(int i = 1 ; i <= n ; i ++){
        int now = k - c[i];///缺多少个数
        if(now > pre[i - 1]) ///如果前面的数不够的话,后面也要拿
            ans = min(ans , pre[i - 1] * (b[i] - 1) - pre_sum[i - 1] + nex_sum[i + 1] - nex[i + 1] * (b[i] + 1 ) + now);
        else ///前面的数都变成b[i] - 1 ,然后再变now个 , 
            ans = min(ans , pre[i - 1] * (b[i] - 1) - pre_sum[i - 1] + now);
        if(now > nex[i + 1]) 
            ans = min(ans , pre[i - 1] * (b[i] - 1) - pre_sum[i - 1] + nex_sum[i + 1] - nex[i + 1] * (b[i] + 1 ) + now);
        else 
            ans = min(ans , nex_sum[i + 1] - nex[i + 1] * (b[i] + 1)  + now);
    }
    cout << ans << '\n';
    return 0;
}
View Code

 

 

 

待补

posted @ 2020-03-29 20:23  GoodVv  阅读(167)  评论(0编辑  收藏  举报