1 条题解

  • 0
    @ 2026-4-6 12:05:16

    A.发生次数相等

    题目重述

    给定一个非递减的数组 aa,长度为 nn
    定义平衡数组:数组中每个不同的元素出现的次数都相等。
    aa最长平衡子序列的长度。

    注意:子序列可以不连续,但保持原顺序(本题因为非递减,顺序无关紧要,我们只关心元素种类和频次)。


    思路分析

    因为数组是非递减的,所以相同的元素一定连续出现。
    设数组中有 kk 种不同的元素,第 ii 种元素出现的次数为 cic_i,且 c1,c2,,ckc_1, c_2, \dots, c_k 已知。

    我们想选一个子序列,使得选中的元素种类中,每种元素出现的次数相同。
    换句话说,如果我们选择了 mm 种元素,那么每种元素必须选相同的次数 ff,子序列长度就是 m×fm \times f


    关键观察

    • 对于每种元素,我们最多能选它的全部出现次数 cic_i
    • 如果我们决定让每种选中的元素出现 ff 次,那么能选这种元素的充要条件是 cifc_i \ge f
    • 所以对于给定的 ff,我们能选出的元素种类数 = 满足 cifc_i \ge f 的不同元素的数量。

    count[f]count[f] = 出现次数 f\ge f 的元素种类数。
    那么长度为 f×count[f]f \times count[f] 的平衡子序列是可行的(从每种满足条件的元素中任选 ff 个)。

    我们只需枚举 ff11nnff 不能超过最大出现次数),计算 f×count[f]f \times count[f] 的最大值即可。


    算法步骤

    1. 遍历数组,统计每种元素的出现次数,存入数组 freqfreq(因为非递减,可以边遍历边统计)。
    2. maxf=max(freq)maxf = \max(freq)
    3. ff11maxfmaxf
      • 统计 freqfreqf\ge f 的个数,记为 cntcnt
      • 更新答案 ans=max(ans,f×cnt)ans = \max(ans, f \times cnt)
    4. 输出 ansans

    复杂度:O(n2)O(n^2) 最坏(n100n \le 100 完全可行),也可以优化到 O(nlogn)O(n \log n),但没必要。


    举例验证

    例1

    a=[1,1,4,4,4]a = [1,1,4,4,4]
    频次:11 出现 22 次,44 出现 33 次。

    f=1f=11\ge 1 的种类有 22 种 → 长度 1×2=21 \times 2 = 2
    f=2f=22\ge 2 的种类有 22 种 → 长度 2×2=42 \times 2 = 4
    f=3f=33\ge 3 的种类有 11 种 → 长度 3×1=33 \times 1 = 3
    最大是 44,输出 44


    例2

    a=[1,2]a = [1,2]
    频次:11 出现 11 次,22 出现 11 次。

    f=1f=11\ge 1 的种类有 22 种 → 长度 22
    最大是 22,输出 22


    例3

    a=[1,1,1,1,1,2,2,2,2,3,3,3,4,4,5]a = [1,1,1,1,1,2,2,2,2,3,3,3,4,4,5]
    频次:1:5, 2:4, 3:3, 4:2, 5:11:5,\ 2:4,\ 3:3,\ 4:2,\ 5:1

    f=1f=1:种类 55 → 长度 55
    f=2f=2:种类 44(1,2,3,4) → 长度 88
    f=3f=3:种类 33(1,2,3) → 长度 99
    f=4f=4:种类 22(1,2) → 长度 88
    f=5f=5:种类 11(1) → 长度 55
    最大是 99,输出 99


    题解代码(对应标程思路)

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    int main() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            vector<int> a(n);
            for (int i = 0; i < n; i++) {
                cin >> a[i];
            }
    
            // 统计频次
            vector<int> freq;
            int cnt = 1;
            for (int i = 1; i < n; i++) {
                if (a[i] == a[i - 1]) {
                    cnt++;
                } else {
                    freq.push_back(cnt);
                    cnt = 1;
                }
            }
            freq.push_back(cnt);
    
            int maxf = *max_element(freq.begin(), freq.end());
            int ans = 0;
    
            for (int f = 1; f <= maxf; f++) {
                int kinds = 0;
                for (int c : freq) {
                    if (c >= f) kinds++;
                }
                ans = max(ans, f * kinds);
            }
    
            cout << ans << "\n";
        }
        return 0;
    }
    

    复杂度分析

    • 时间复杂度:O(n×maxf)O(n \times \text{maxf}),最坏 O(n2)O(n^2)n100n \le 100 完全可行。
    • 空间复杂度:O(n)O(n)

    总结

    本题的核心是枚举“每种元素出现的次数”ff,然后看有多少种元素能达到这个次数,乘起来就是该 ff 下能获得的最长平衡子序列长度,最后取最大值。
    因为数组非递减,统计频次很方便,且 nn 很小,直接枚举即可。

    • 1

    信息

    ID
    6227
    时间
    1000ms
    内存
    256MiB
    难度
    2
    标签
    递交数
    4
    已通过
    1
    上传者