1 条题解
-
0
B. 组成三角形 题解
1. 题目回顾
我们有 根棍子,第 根的长度为 ,其中 是非负整数。我们需要从中选出 根棍子组成一个非退化三角形(面积大于 )。求方案数。选取顺序无关。
2. 三角形条件的转化
设三根棍子的长度分别为 、、,不妨假设 。根据三角形不等式,能组成非退化三角形的充要条件是:
由于 的幂次增长速度很快,我们来分析不同情况:
情况 1:
此时 ,显然成立。因此任意三根长度相同的棍子都能组成三角形。
情况 2:
此时不等式变为 ,等价于 ,但这与假设 矛盾。所以不存在两短一长的情况能构成三角形。
情况 3:
此时 恒成立(因为 )。因此只要有两根较长的棍子长度相等,另一根较短的任意长度都可以构成三角形。
情况 4:
此时 ,无法严格大于。所以三边长度互不相等时不可能构成三角形。
结论
能构成三角形的三根棍子,其长度指数必须满足以下条件之一:
- 三个指数全相同;
- 恰好有两个指数相同(第三个指数可以任意,但由上述分析知第三个指数必须小于或等于相同的指数;若第三个指数等于相同指数,即三个相同,已归入情况1;若小于,则符合 的形式)。
简而言之:选出的 个指数不能两两不同。
3. 组合计数方法
设数组 中不同值的出现次数分别为 (按值从小到大排序)。我们遍历每个不同的值,累加贡献。
对于当前值 ,设其出现次数为 ,在此之前已经遍历过的所有元素总数为 (即比 小的值的出现次数总和)。
-
选择三根长度均为 的棍子:贡献为 $\binom{cnt}{3} = \frac{cnt \cdot (cnt-1) \cdot (cnt-2)}{6}$。
-
选择两根长度为 的棍子,搭配一根长度小于 的棍子:两根长度 的选法有 种,第三根可从前面 根中任选一根,贡献为 。
注意:当选择两根长度 的棍子并搭配一根长度等于 的棍子时,等价于三根长度均为 ,已经在第一种情况中计算过,故这里第三根只从小于 的棍子中选取,避免重复计数。
遍历完当前值后,将 累加到 中,继续处理下一个值。
最后输出总方案数。
4. 时间复杂度
- 统计频率需要 时间,可以用
map或排序后计数。 - 遍历不同值的数量不超过 ,每次计算 。
- 总时间复杂度 或 (取决于统计方式),在 的限制下完全可行。
5. C++ 代码实现
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n; cin >> n; map<int, int> freq; for (int i = 0; i < n; ++i) { int x; cin >> x; ++freq[x]; } long long ans = 0; int sum = 0; // 记录比当前值小的元素总数 for (auto &[val, cnt] : freq) { if (cnt >= 3) { ans += 1LL * cnt * (cnt - 1) * (cnt - 2) / 6; } if (cnt >= 2) { ans += 1LL * cnt * (cnt - 1) / 2 * sum; } sum += cnt; } cout << ans << '\n'; } return 0; }6. 样例验证
以样例2为例:,数组为 。
频率统计:,,。
- 处理 :,跳过。
- 处理 :,跳过。
- 处理 :,(前面 和 各 个)。贡献为 。
答案 ,与输出一致。
7. 总结
本题的关键是将几何条件(三角形不等式)转化为对指数相等关系的组合条件。利用幂次的性质简化了分类讨论,最终只需简单的组合计数即可求解。代码实现简洁高效。
- 1
信息
- ID
- 6519
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者