• CF-1328 F. Make k Equal


    F. Make k Equal

    题目链接

    题意

    长度为n的序列,每次可以选择一个最大的数字将其减一或者选择一个最小的数字将其加一,问最少操作多少次可以使得序列中至少存在 k 个一样的数字

    分析

    官方题解:http://codeforces.com/blog/entry/75246

    可以想到最后一样的数字,一定是在原序列里面出现的,所以将原数组离散化之后,枚举最后一样的数字,并努力把它凑够 k 个。如何凑?借助左侧或者右侧的数字。只要借助了某侧的数字,那么这一侧全部的数字都要先挪动它旁边的那个位置,然后再按照需要搬到当前这个位置上来。

    所以最后只会有两种方案:优先选左侧或者优先选右侧,我们都试一下就好了,结果取最小(计算细节可以参考代码以及官方题解)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    #define dbg(x...) do { cout << "33[32;1m" << #x <<" -> "; err(x); } while (0)
    void err() { cout << "33[39;0m" << endl; }
    template<class T, class... Ts> void err(const T& arg,const Ts&... args) { cout << arg << " "; err(args...); }
    const int N = 200000 + 5;
    int n, k, a[N];
    vector<int> v;
    ll cnt[N], sum[N];
    ll pre[N];
    
    int main(){
        scanf("%d%d", &n, &k);
        for(int i=1;i<=n;i++){
            scanf("%d", &a[i]);
            v.push_back(a[i]);
        }
        v.push_back(0);
        sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());
        for(int i=1;i<=n;i++){
            int id = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
            cnt[id] ++;
        }
        n = v.size()-1;
        for(int i=1;i<=n;i++) {
            sum[i] = sum[i-1] + cnt[i];
            pre[i] = pre[i-1] + cnt[i] * v[i];
        }
        ll res = pre[n];
        for(int i=1;i<=n;i++){
            ll need = max(0ll, k - cnt[i]);
            // 先左后右
            {
                ll tmp = 0;
                int lnum = min(need, sum[i-1]);
                // 只有当lnum>0时才需要计算,下面同理
                if(lnum){
                    tmp = sum[i-1] * (v[i]-1) - pre[i-1];
                    tmp += lnum;
                }
                int rnum = min(need-lnum, sum[n] - sum[i]);
                if(rnum){
                    tmp += (pre[n] - pre[i]) - (sum[n]-sum[i]) * (v[i]+1);
                    tmp += rnum;
                }
                res = min(res, tmp);
            }
            // 先右后左
            {
                ll tmp = 0;
                int rnum = min(need, sum[n] - sum[i]);
                if(rnum){
                    tmp = (pre[n] - pre[i]) - (sum[n] - sum[i]) * (v[i]+1);
                    tmp += rnum;
                }
                int lnum = min(need-rnum, sum[i-1]);
                if(lnum){
                    tmp += sum[i-1] * (v[i]-1) - pre[i-1];
                    tmp += lnum;
                }
                res = min(res, tmp);
            }
        }
        cout << res << endl;
        return 0;
    }
    

    2400难度的题目,平常心看待就好了

  • 相关阅读:
    PHP做Web开发的MVC框架(Smarty使用说明 )
    PHP + Smarty + html5 构建Wap应用
    HTML5游戏中动画帧的概念理解
    [转]jQuery选择器 (详解)
    2014马年应该有怎么样的学习方式和思考原则
    html5视频播放解决方案
    html5学习摘要
    sqlserver2008行锁
    关于一些url中传递参数有空格问题
    MongoDB和Redis区别
  • 原文地址:https://www.cnblogs.com/1625--H/p/12639963.html
Copyright © 2020-2023  润新知