题目背景
上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来。
题目描述
有 nnn 根木棒,现在从中选 444 根,想要组成一个正三角形,问有几种选法?
答案对 109+710^9+7109+7 取模。
输入格式
第一行一个整数 nnn 。第二行 nnn 个整数,第 iii 个整数 aia_iai 代表第 iii 根木棒的长度。
输出格式
一行一个整数代表答案。
输入输出样例
输入 #1
4
1 1 2 2
输出 #1
1
说明/提示
数据规模与约定
- 对于 30%30\%30% 的数据,保证 n≤5×103n \le 5 \times 10^3n≤5×103。
- 对于 100%100\%100% 的数据,保证 1≤n≤1051 \leq n \le 10^51≤n≤105,0≤ai≤5×1030 \le a_i \le 5 \times 10^30≤ai≤5×103 。
解法 枚举+哈希表+组合
这道题有点意思。由于要用 444 根木棒组成正三角形,就必须要有两根木棒长度相等,剩下的一边,则由 222 根长度之和等于 前 222 根相等的木棒的长度 的木棒组成。
由于木棒长度 ai≤5000a_i \le 5000ai≤5000 ,用 O(n2)O(n^2)O(n2) 的算法就能过,于是直接两重循环,暴力枚举上述两种木棒的长度,计算组合方案数并累加。
此处外层循环 cnt[]cnt[]cnt[] 数组,cnt[i]cnt[i]cnt[i] 为长度为 iii 的木棒的个数。要从 cnt[i]cnt[i]cnt[i] 根长度为 iii 的木棒中取出 222 根,即计算组合数 C(cnt[i],2)C(cnt[i], 2)C(cnt[i],2);内层循环中,要从剩余的木棒中取出两根长度之和为 iii 的木棒,令一根长度为 jjj ,另一根长度则为 i−ji - ji−j ,为避免重复计算,设 j≤i−jj \le i - jj≤i−j 。分类讨论:
- j==i−jj == i - jj==i−j 时,从长度为 jjj 的木棍中取出 222 根合为一条边, 方案数为 C(cnt[j],2)C(cnt[j], 2)C(cnt[j],2) ;
- j≠i−jj \ne i - jj=i−j 时,从长度为 jjj 和长度为 i−ji- ji−j 的木棍中各取出一根,方案数为 C(cnt[j],1)×C(cnt[i−j],1)C(cnt[j], 1) \times C(cnt[i - j], 1)C(cnt[j],1)×C(cnt[i−j],1)
将所有外层方案数和内层方案数的乘积汇总,就是总的方案数。不过题目中有些地方描述不清楚, aia_iai 可以为 000 ,那么可以用三根长度一样的木棍加上一根长度为零的木棍,可以组成一个正三角形吗?三根长度为零的木棍,可以组成正三角形吗?尝试提交了几次,从AC代码中发现,这些情况是不允许的:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3 + 10, mod = 1e9 + 7;
int n, t, cnt[maxn], maxLen = 0, ans = 0;
bool flag = true; //所有长度的木棍都是唯一的
int C(int n, int k) { //n个数中选出k个数的组合数
return (k == 1 ? n : n * (n - 1) / 2) % mod; //k要么为1,要么为2
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &t);
++cnt[t];
if (cnt[t] > 1) flag = false;
maxLen = max(maxLen, t); //最长的木棍长度
}
if (flag) { printf("0"); return 0; } //所有长度的木棍都是唯一的,无法组成正三角形
for (int i = 2; i <= maxLen; ++i) { //枚举外层的两根长度为i的木棍组合
if (cnt[i] <= 1) continue; //枚举内层的一根木棍长度为j,另一根长度为i-j
int times = C(cnt[i], 2) % mod;
for (int j = 1; j <= i / 2; ++j) { //注意避免重复计算,令j<=i-j
// if (j == 0 && cnt[j] >= 1 && cnt[i] >= 3)
// ans += C(cnt[i], 3) * C(cnt[j], 1);
if (j == i - j && cnt[j] >= 2)
ans += times * C(cnt[j], 2) % mod;
else if (j != i - j && cnt[j] >= 1 && cnt[i - j] >= 1)
ans += times * C(cnt[j], 1) * C(cnt[i - j], 1) % mod;
ans %= mod;
}
}
printf("%d\n", ans);
return 0;
}


这是一篇关于编程竞赛的博客,主要探讨了一道题目,要求使用4根木棒组成一个正三角形。解法涉及到枚举和哈希表,通过两层循环计算不同组合,并对结果取模。文章提到了数据规模和限制条件,并给出了AC代码示例,解释了代码中的关键逻辑和注意事项。
852





