『题解』CF1490F Equalize the Array

无良商家推送blog这里阅读效果更佳

题意

二次元跨界量子超级传送门

二次元来了!快跑!

一天,雷姆姐姐在修剪花园。罗兹沃尔的花园非常豪华,而且都是由雷姆姐姐一手操办。傲娇~(不是

但是罗兹沃尔的强迫症又犯了,他不希望自己花园非常的凌乱,他希望自己花园中不同种类的花数目相同,所以安排雷姆姐姐帮他处理花园中的花。

然鹅雷姆姐姐每天都要和你玩耍努力工作,非常劳累,热心肠的你决定帮助她。

你可以帮雷姆把多余的花剪走,使得最后花园中不同种类的花数目相同。

问达成目的最少的操作数。

话说这样的题面你们不喜欢么。。。那还不赶紧点赞

解析

显然是要寻找一条界限,使得界限以上的不同元素出现次数相等界限一下的元素删至数目为零,直接枚举寻找这条界线就好了。

可以考虑对元素数据进行离散化,然后桶排序,将各个元素出现的次数记录到几个 \(bkt[i] \ ( bucket )\) 里,然后可以进行两种操作:

  • 判断在界限以上的元素数目删除到界限值

  • 判断在界限一下的元素数目直接清除,也就是删除到 \(0\)

然而直接挨个删除元素会超时,考虑如何进行优化。

不都已经把各种元素出现次数统计下来了吗,事先处理前缀和不就好了嘛~

所以删除次数显然易见:

  • 界限以上的元素所需的删除次数就是前缀和

  • 界限一下的元素删除次数是用前缀和减去这些元素的个数 \(\times\) 界限值

你们最爱的环节

/*

Name: CF1490F Equalize the Array

By Frather_

*/
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>

#define InF 0x3f3f3f3f

using namespace std;
/*=========================================快读*/
int read() //快读不解释
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
/*=====================================定义变量*/
int T;

int n;
int a[300030], a_[300030];

int n_; //记录界限值

int bkt[300030];
int sum[300030]; //记录前缀和

int ans[300030], ans_[300030];
int res = InF; //最终结果
/*====================== =============自定义函数*/
void prepare() //多组数据,清空变量
{
    n = 0;
    memset(ans, 0x3f, sizeof(ans));
    memset(ans_, 0x3f, sizeof(ans_));
    n_ = 0;
    memset(bkt, 0, sizeof(bkt));
    memset(sum, 0, sizeof(sum));
    res = InF;
}
/*=======================================主函数*/
int main()
{
    T = read();
    while (T--)
    {
        prepare();

        n = read();
        for (int i = 1; i <= n; i++) //读入数据,动态复制一组数据,利于下面的离散化
        {
            a[i] = read();
            a_[i] = a[i];
        }

        sort(a_ + 1, a_ + n + 1);

        n_ = unique(a_ + 1, a_ + n + 1) - a_ - 1;

        for (int i = 1; i <= n; i++) //离散化没什么解释的
            a[i] = lower_bound(a_ + 1, a_ + n_ + 1, a[i]) - a_;
        for (int i = 1; i <= n; i++) //桶排序记录元素出现次数
            bkt[a[i]]++;

        sort(bkt + 1, bkt + n_ + 1);

        for (int i = 1; i <= n_; i++)
            sum[i] = sum[i - 1] + bkt[i];
        for (int i = 1; i <= n; i++)
        {
            int t = lower_bound(bkt + 1, bkt + n_ + 1, i) - bkt;
            if (t > n_) //界限以上
                ans[i] = sum[n_];
            if (t < n_) //界限一下
                ans_[i] = sum[t - 1] + sum[n_] - sum[t - 1] - (n_ - t + 1) * i;
        }

        for (int i = 1; i <= n; i++) //统计答案
            res = min(res, min(ans[i], ans_[i]));
        printf("%d\n", res);
    }
    return 0;
}

友情提示

\[多组数据一定要记得清空变量!!! \]

\[多组数据一定要记得清空变量!!! \]

\[多组数据一定要记得清空变量!!! \]

别问我为什么这么说。。。有苦有泪我不说

原文地址:https://www.cnblogs.com/Frather/p/14430746.html