1 条题解
-
0
A.发生次数相等
题目重述
给定一个非递减的数组 ,长度为 。
定义平衡数组:数组中每个不同的元素出现的次数都相等。
求 的最长平衡子序列的长度。注意:子序列可以不连续,但保持原顺序(本题因为非递减,顺序无关紧要,我们只关心元素种类和频次)。
思路分析
因为数组是非递减的,所以相同的元素一定连续出现。
设数组中有 种不同的元素,第 种元素出现的次数为 ,且 已知。我们想选一个子序列,使得选中的元素种类中,每种元素出现的次数相同。
换句话说,如果我们选择了 种元素,那么每种元素必须选相同的次数 ,子序列长度就是 。
关键观察
- 对于每种元素,我们最多能选它的全部出现次数 。
- 如果我们决定让每种选中的元素出现 次,那么能选这种元素的充要条件是 。
- 所以对于给定的 ,我们能选出的元素种类数 = 满足 的不同元素的数量。
设 = 出现次数 的元素种类数。
那么长度为 的平衡子序列是可行的(从每种满足条件的元素中任选 个)。我们只需枚举 从 到 ( 不能超过最大出现次数),计算 的最大值即可。
算法步骤
- 遍历数组,统计每种元素的出现次数,存入数组 (因为非递减,可以边遍历边统计)。
- 令 。
- 对 从 到 :
- 统计 中 的个数,记为 。
- 更新答案 。
- 输出 。
复杂度: 最坏( 完全可行),也可以优化到 ,但没必要。
举例验证
例1
频次: 出现 次, 出现 次。: 的种类有 种 → 长度
: 的种类有 种 → 长度
: 的种类有 种 → 长度
最大是 ,输出 。
例2
频次: 出现 次, 出现 次。: 的种类有 种 → 长度
最大是 ,输出 。
例3
频次::种类 → 长度
:种类 (1,2,3,4) → 长度
:种类 (1,2,3) → 长度
:种类 (1,2) → 长度
:种类 (1) → 长度
最大是 ,输出 。
题解代码(对应标程思路)
#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; }
复杂度分析
- 时间复杂度:,最坏 , 完全可行。
- 空间复杂度:。
总结
本题的核心是枚举“每种元素出现的次数”,然后看有多少种元素能达到这个次数,乘起来就是该 下能获得的最长平衡子序列长度,最后取最大值。
因为数组非递减,统计频次很方便,且 很小,直接枚举即可。
- 1
信息
- ID
- 6227
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者