• 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 << '
    ' , 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 << '
    ';
        return 0;
    }
    View Code

    待补

  • 相关阅读:
    阅读之分布式架构的数据一致
    阅读之MySQL数据库分表
    阅读笔记1
    问题账户需求分析
    软件需求分析阅读笔记
    开发进度第四天
    开发进度第三天
    开发进度第二天
    线程中三个关键对象闭锁,栅栏,信号量
    java多线程中关于原子操作
  • 原文地址:https://www.cnblogs.com/GoodVv/p/12594520.html
Copyright © 2020-2023  润新知