Equalize the Array(思维)

题目链接: Equalize the Array

大致题意

给定一个长度为n的序列, 要求删除序列中尽可能少的元素, 使得剩余序列中出现的每一个元素数量相同.

解题思路

首先最终的序列, 一定是所有的元素都剩余x个. 那么在进行处理的时候, 原本有>x个的元素, 会把多余的部分删除, <x个的元素, 会全部都删除.

对于x, 这里要说明的是, 令集合st = { 所有元素出现次数(小到大排序过了) }, x一定是st中的某个元素. 这里用(num, cou)表示num这个数字出现cou次. 例如序列可以简化为 (3, 5), (4, 2), (1, 3), (9, 2). 那么一定满足 x ∈ { 2, 3, 5 };

证明: 不妨令 x = y (y ∈ st), 而 (y - 1) ∉ st && (y + 1) ∉ st.
​ ①当x = y + 1时, 那么对于出现次数<y的部分不变, 对于=y的部分, 对结果的贡献会增加a, 对于>y的部分, 对结果的贡献会减少b, 最终对结果的影响为delta = a - b. 这样我们看似是无法确定a和b的关系的, 但是我们注意到, 如果在st中找到y的后继y’, 此时对结果的影响(相较于x = y的情况)记为delta’ = a - b’, 此时一定满足b’ >= b. 则我们实际会在x = y’处得到比x = y + 1的更优解.

​ ②当x = y - 1时, 其实和情况①是相似的, 只是把两种情况对掉了, 我们会发现在y处取到更优解.

综上所述: 我们可以得出结论, x ∈ st;


此时我们考虑, 如果通过枚举x的方式, 枚举次数和st中的元素个数有关, 最坏情况: st = { 1, 2, 3, … }; 此时集合中的元素和为等差数列, 是n2级别的, 那么st中的元素个数就为√n级别.

在进行枚举x时, 对于当前x = y的情况, 此时要删除<y的所有元素, 和>y的元素多余的那部分.

我的做法: 我们不妨从大到小进行枚举x, 每次统计出现次数>=x的数字总数num, 最终都要使得他们变成x次, 相当于剩余元素的个数leave = x * num, 那么删除的元素个数del = n - leave. 是可以做到常数级别实现的.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
#define debug(a) cout << #a << " = " << a << endl;
using namespace std;
typedef long long ll;
map<int, int> mp1; //用于统计每个数字出现的次数.
map<int, int, greater<int>> mp2; //用于统计出现first次的数字有second个
int main()
{
    int t; cin >> t;
    while (t--) {
        mp1.clear(), mp2.clear();
        
        int n; scanf("%d", &n);
        rep(i, n) {
            int x; scanf("%d", &x);
            mp1[x]++;
        }
        for (auto& [x, y] : mp1) mp2[y]++;
        
        int res = 0x3f3f3f3f; 
        int bin = 0; //记录已经统计过的数字种类
        for (auto& [cou, num] : mp2) {
            bin += num;
            int del = n - cou * bin;
            res = min(res, del);
        }
        printf("%d\n", res);
    }
    return 0;
}

END

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值