洛谷 P3799 妖梦拼木棒【枚举/组合数学】
题目背景
上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来。
题目描述
有 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-jint 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;
}
洛谷 P3799 妖梦拼木棒【枚举/组合数学】相关推荐
- 【题解】【算法】- 洛谷 - P3799 妖梦拼木棒(组合数学)
题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有 n 根木棒,现在从中选 4 根,想要组成一个正三角形,问有几种选法? 答案对 109 + 7 取模. 输入格式 第一行一 ...
- 洛谷[P3799 妖梦拼木棒] {暴力枚举} 奋斗的珂珂~
洛谷[P3799 妖梦拼木棒] {暴力枚举} 题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有 n 根木棒,现在从中选 4 根,想要组成一个正三角形,问有几种选法? 答案 ...
- P3799 妖梦拼木棒——枚举+组合数学
妖梦拼木棒 题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有 nnn 根木棒,现在从中选 444 根,想要组成一个正三角形,问有几种选法? 答案对 109+710^9+7 ...
- 洛谷-P3799 妖梦拼木棒
题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有 nn 根木棒,现在从中选 44 根,想要组成一个正三角形,问有几种选法? 答案对 10^9+7109+7 取模. 输入格 ...
- 洛谷P3799 妖梦拼木棒
题目链接 题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有n根木棒,现在从中选4根,想要组成一个正三角形,问有几种选法? 输入格式: 第一行一个整数n 第二行n个整数,a ...
- 洛谷P3799 妖梦拼木棒 题解
//简单的思路:四根必有两根相同,所以咱们就先选两根组合成第三根,确定另外相同的两根的长度 //分为两种情况,一.预选两根相同长度.二.预选两根不同长度. //所有情况是预选*(确定的另外两根) #i ...
- 洛谷 P3799 妖梦拼木棒
题目 这道题主要考组合数学,一开始我没注意数据范围,傻乎乎地模拟,结果复杂度爆炸10个TLE.这道题是算出来的. 思路是用一个栈把相同长度个数超过2的木棍用栈保存下来,同时用一个数组存下所有长度木棍的 ...
- [luogu P3799] 妖梦拼木棒
[luogu P3799] 妖梦拼木棒 题目描述 解决过程 思路 代码 感想 题目描述 点击此处查看题目描述 解决过程 暴力不多阐述,很显然是无法AC的 解决此题需要用到组合数 思路 这道题要求拼成等 ...
- 洛谷 P3797 妖梦斩木棒 解题报告
P3797 妖梦斩木棒 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的\(n\)段.现在这个木棒可以看做 ...
最新文章
- 理解与使用Javascript中的回调函数
- Linux shell script 的语法汇总
- python深浅拷贝的底层理解_理解python中的深拷贝与浅拷贝
- 【转】使用Jmeter针对ActiveMQ JMS Point To Point压力测试
- 【OS学习笔记】三十七 保护模式十:中断和异常的处理与抢占式多任务对应的汇编代码----主引导扇区代码
- c form画直线_新手教程跟我一起画儿童裤子裁剪图
- 预测评价系统_「机器学习」一文读懂分类算法常用评价指标
- 【Spring笔记】Spring配置
- 【脑洞大开】假如BERT系列论文变成Commit History
- 研制埃博拉疫苗与科学家的奇思秒想
- ezd激光雕刻机软件使用笔记。
- 你不知道的华为交换机22个实用技巧
- 从Java程序员到架构师,从工程师到技术专家,迷茫之路
- Kotlin Flow详解
- 华为H3CNE认证题库、教材-热门下载帖汇总!
- P4839 P哥的桶 题解
- 如何做好App性能测试
- 对于Spring MCV的理解
- 和chatGPT聊了聊通信,答复如下:
- 【文献翻译】Epileptic Seizures Detection Using Deep Learning Techniques: A Review