zoukankan      html  css  js  c++  java
  • 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难度的题目,平常心看待就好了

  • 相关阅读:
    安装sublime text2 for ubuntu
    ruby中Regexp用法
    rvm is not a function的解决方法
    解决启动mongod 时,出现addr already in use错误
    rails中常用的插件
    在数据库中存储层次数据
    Formtastic: Forms Made Crazy Easy for Rails Developers
    rails安全性
    Rails 增加一个模型(model)
    RPC框架实现思路浅析
  • 原文地址:https://www.cnblogs.com/1625--H/p/12639963.html
Copyright © 2011-2022 走看看