1 条题解
-
0
题目理解
我们有一个长度为 的数组 ,初始分数为 。每次操作可以选择两个之前都没被选过的下标 和 (),且满足 ,然后分数加 。问最多能获得多少分。
关键观察
. 元素独立配对
由于每次操作选择两个下标,且要求它们对应的数值相等,不同数值之间的操作不会互相影响。因此,我们可以分别考虑每个数值 。. 频率计数
设 表示数值 在数组 中出现的次数。
每次选择两个相等的数值 ,就会消耗掉两个值为 的元素。
因此,对于数值 ,最多能进行的操作次数是 (即两两配对后剩余不足一对的无法使用)。. 总分数
$$\text{ans} = \sum_{x} \left\lfloor \frac{f_x}{2} \right\rfloor $$
总分数就是所有不同数值 能配对的次数之和:其中 的取值范围是数组中出现过的所有数值。
算法步骤
. 读入测试数据组数 。 . 对每组测试数据:
- 读入 和数组 。
- 因为题目保证 ,所以可以开一个长度为 的计数数组 ,用于统计每个数值的出现次数。
- 遍历数组 ,对于每个 ,执行 。
- 遍历 从 到 ,将 累加到答案中。
- 输出答案。
时间复杂度
- 每组数据遍历数组一次统计频率:。
- 遍历数值范围计算答案:。
- 总复杂度 ,在 , 的条件下完全可行。
示例验证
以输入:
4 1 2 3 1为例:
- 数值 出现 次 →
- 数值 出现 次 →
- 数值 出现 次 →
- 答案 = ,与题目输出一致。
代码实现
#include <iostream> #include <vector> using namespace std; int main() { int t; cin >> t; while (t--) { int n; cin >> n; vector<int> a(n); vector<int> cnt(n + 1, 0); // 统计每个数值出现的次数,范围 1..n for (int i = 0; i < n; i++) { cin >> a[i]; cnt[a[i]]++; } int ans = 0; for (int x = 1; x <= n; x++) { ans += cnt[x] / 2; // 每对相同的数贡献 1 分 } cout << ans << endl; } return 0; }
- 1
信息
- ID
- 6286
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者