1 条题解

  • 0
    @ 2026-8-13 14:11:01

    /* 可以发现题目中只关注一个数字的出现次数,而不关心这个数字的大小 所以我们可以将所有数字的出现次数进行统计,然后将所有数字的出现次数记录为 bb 数组 这一步可以将 aa 数组排序,也可以直接使用 mapmap 进行统计 然后我们要做的事情就是保留下 bb 数组中差值不超过 mm 的一段,然后删去其他的部分即可 那么很容易想到我们可以将 bb 数组进行排序,那么保留的一定是连续的一段,删除的就是头尾部分了,用一个前缀和就可以快速计算需要删除的数字数量了 那么关于枚举连续的一段,我们可以用双指针 l,rl,r 进行枚举,也可以直接对于 ii 二分查找一个第一个 b[i]+mb[i] + m 但是这里要注意一个问题,那就是对于我们找出的数字区间 b[l]b[r]b[l] \sim b[r] 而言,我们需要进行的操作应该是将 1b[l1]1 \sim b[l-1] 的数字删光,对于 b[r]\ge b[r] 的数字并不需要全部删光,只要删到 b[l]+mb[l] + m 即可,这是一个坑,要注意 那么对于一个区间 b[l]b[r]b[l] \sim b[r] 而言,最终保留的数字数量应该是 ans=sum[r]sum[l1]+(lenr)(b[l]+m)ans = sum[r] - sum[l-1] + (len - r) * (b[l] + m) 然后对 nansn - ans 求最小值即可 */ #include<bits/stdc++.h>

    using namespace std;

    map<int, int> cnt;
    int a[100010], n, m, x, len, ans = 1e9, s[100010]; int main() { freopen("put.in","r",stdin); freopen("put.out","w",stdout); scanf("%d%d", &n, &m); for (int i = 0; i < n; i++){ cin >> x; cnt[x]++; } for (map<int, int>::iterator i = cnt.begin(); i != cnt.end(); ++i){ a[++len] = i->second; } sort(a + 1, a + len + 1); for (int i = 1; i <= len; i++){ s[i] = s[i - 1] + a[i]; } for (int i = 1; i <= len; i++){ int j = upper_bound(a + i, a + len + 1, a[i] + m) - a - 1; int sum = s[j] - s[i - 1] + (len - j) * (a[i] + m); ans = min(ans, n - sum); } printf("%d\n", ans); return 0; }

    • 1

    信息

    ID
    9995
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    35
    已通过
    6
    上传者