【题解】【枚举,数学】——小 Y 拼木棒


前置知识:排列组合,暴力枚举基础知识。

小 Y 拼木棒

通往洛谷的传送门

题目背景

上道题中,小 Y 斩了一地的木棒,现在她想要将木棒拼起来。

题目描述

n n n 根木棒,现在从中选 4 4 4 根,想要组成一个正三角形,问有几种选法?

答案对 1 0 9 + 7 10^9+7 109+7 取模。

输入格式

第一行一个整数 n n n

第二行往下 n n n 行,每行 1 1 1 个整数,第 i i i 个整数 a i a_i ai 代表第 i i i 根木棒的长度。

输出格式

一行一个整数代表答案。

输入输出样例

输入 #1

4 
1
1
2
2

输出 #1

1

提示

数据规模与约定
  • 对于 30 % 30\% 30% 的数据,保证 n ≤ 5 × 1 0 3 n \le 5 \times 10^3 n5×103
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 1 0 5 1 \leq n \le 10^5 1n105 1 ≤ a i ≤ 5 × 1 0 3 1 \le a_i \le 5 \times 10^3 1ai5×103

关于标题:因为一些不可抗力的原因,名称进行了更改。深表歉意。

1.题意简述

    找出四个数 a , b , c , d a,b,c,d a,b,c,d,求出有多少组这样的数使得 a = b = c + d ( c ≤ d ) a=b=c+d(c\leq d) a=b=c+d(cd)

2.思路解析

    大部分人第一时间想到的就是直接暴力枚举。使用枚举子集的方法,暴力枚举四条木棍的长度然后再判断。但是一看数据范围 n ≤ 1 0 5 n\leq 10^5 n105,那么用 O ( 2 n ) O(2^n) O(2n)的算法显然是不行的。要考虑优化。

    因为组成三角形跟相同长度的木棍有关,首先使用类似于计数排序的方法,用pail[i]储存长度为i的木棍的根数。

    我们可以考虑枚举 a a a,得到其中两根相同长度的木棍的长度(即ab)。然后再枚举c,通过c来算出 d d d。这样只需要 O ( n 2 ) O(n^2) O(n2)的时间复杂度就搞定了。

    枚举 c c c的时候,分两种情况讨论。第一种情况是c=d。这个时候,就相当于从长度为 c c c的木棍里选取两根,与在长度为 a a a的木棍中选取的两根 a a a b b b)组成一个三角形。这不就是计算组合数吗?即 C p a i l [ a ] 2 ∗ C p a i l [ c ] 2 C_{pail[a]}^2*C_{pail[c]}^2 Cpail[a]2Cpail[c]2

    再来看看第二种情况,c!=d。这个时候,就是从长度为c的木棍中选取一根,再从长度为d的木棍中选取一根,与在长度为 a a a的木棍中选取的两根组成一个三角形。即 C p a i l [ a ] 2 ∗ p a i l [ c ] ∗ p a i l [ d ] C_{pail[a]}^2*pail[c]*pail[d] Cpail[a]2pail[c]pail[d]

    现在再来看看如何计算组合数。可以发现,上面的组合数 C n m C_n^m Cnm只计算了 m = 2 m=2 m=2的情况。我们可以据此化简,并将它封装成一个函数。
C n m = n ! m ! ( n − m ) ! C_n^m=\frac{n!}{m!(n-m)!} Cnm=m!(nm)!n!
    代入 m = 2 m=2 m=2得:
n ! 2 ! ( n − 2 ) ! \frac{n!}{2!(n-2)!} 2!(n2)!n!
    展开得:
1 × 2 × 3 × ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ × ( n − 1 ) × n 1 × 2 × 1 × 2 × 3 × ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ × ( n − 3 ) × ( n − 2 ) \frac{1\times2\times3\times······\times(n-1)\times n}{1\times2\times1\times2\times3\times······\times(n-3)\times(n-2)} 1×2×1×2×3×⋅⋅⋅⋅⋅⋅×(n3)×(n2)1×2×3×⋅⋅⋅⋅⋅⋅×(n1)×n
    化简得:
n ( n − 1 ) 2 = n ( n − 1 ) / 2 \frac{n(n-1)}{2}=n(n-1)/2 2n(n1)=n(n1)/2

    为了方便,我们在后续的代码中将其分装成一个宏函数,不要忘记宏函数的特性哦!

注意

  1. 因为我们是使用来存储数据的,所以 a a a应当枚举到最大范围,即 5 × 1 0 3 = 5000 5×10^3=5000 5×103=5000
  2. 根据我们上面的定义 c ≤ d c\leq d cd,为了避免重复, c c c只需要枚举到a/2
  3. 计算的每一步都要确保长为c和长为d的木棍存在,即pail[c]pail[d]为真;
  4. 记得运算中的每一步都要对1e9+7取模。

3.AC代码

#include<bits/stdc++.h>
using namespace std;
#define C(a) ((a)*((a)-1)/2)//计算组合数C(n,2),记得勤加括号
const int mod=1e9+7;
int main()
{
	int n,pail[5010]={0},cnt=0;//用桶存下木棍的长度 
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int tmp;
		cin>>tmp;
		pail[tmp]++;//放入桶中 
	}
	for(int a=2;a<=5000;a++)//从2开始枚举a 
	{
		for(int c=1;c<=a/2;c++)//c不可能超过a/2
		{
			int d=a-c;
			//随时都要取模
			if(d==c&&pail[a]>=2&&pail[c]>=2)//c和d相同
				cnt+=((C(pail[a])%mod)*(C(pail[c])%mod))%mod;
			else if(d!=c&&pail[a]>=2&&pail[c]&&pail[d])//c和d不相同
				cnt+=((C(pail[a])%mod)*(pail[c]%mod)*(pail[d]%mod))%mod;
			cnt%=mod;
		}
	}
	cout<<cnt%mod;
	return 0;
}

喜欢就订阅此专辑吧!

【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。

欢迎扫码关注蓝胖子编程教育
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝胖子教编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值