P3799 妖梦拼木棒

刚开始我想到了一个3重for循环去找他的剩余木棒,但是可以看到n的范围是10的五次方,如果采用二三重循环,时间复杂度肯定会超过10的8次方

我还想到先排序,使用了一个for循环找到两个相同的ai(排序后肯定是在他旁边的),然后二叉搜索他的差值是否存在(用到了类似组合数学的思想),又wa了

题目分析: 我们可以看到一个木棒的长度最大只有5x10三次方,所以依据木桶效应,对一个取值范围最小的数进行操作。于是我们从一个数出现的次数入手,可以解决这个问题,满足时间复杂度问题。

我们可以想到,选4根木棒成为等边三角形,就是两根要一样大,另两个加起来等于这两根

所以我们是先选两个一样(Cn2)的,然后再一个个枚举是否能找到两根(Cn1 Cn1)加起来是一条边

这里有一个特殊情况

如果剩下的两根的长度是一样的,即选他的概率是Cn2

#include <iostream>
#include <algorithm>
#include <cstring>
int KMOD = 1e9 + 7;
using namespace std;
int n;
int num[5005];
long long ans;
int Cn1(int n)
{
	return n%KMOD;
}
int Cn2(long long n)
{
	return (n * (n - 1) / 2)%KMOD;
}

int main()
{
	int MIN = 1E9, MAX = -1;
	memset(num, 0, sizeof(num));
	ans = 0;
	cin >> n;
	int a;
	for (int i = 0;i < n;i++)
	{
		cin>> a;
		num[a]++;				//这个数的出现次数
		MIN = min(MIN, a);
		MAX = max(MAX, a);
	}

	for (int i = MIN+1;i <=MAX;i++)		//从最小值+1开始寻找有没有两根一样的,到MAX完成剪枝
		if (num[i] >= 2)				//只有有两根一样的时,才会停下来操作
		{//这里的i表示的是木棒的长度,num[i]表示的是长度为i的木棒出现的次数
			for (int j = MIN;2*j <= i;j++)
			{	
				if (j != i - j)			//如果两个j不相等,Cn1
					ans += Cn2(num[i]) * Cn1(num[j]) * Cn1(num[i - j])  % KMOD;
				else if (num[j] >= 2 && j * 2 == i)			//如果j相等  Cn2
					ans += Cn2(num[i])*Cn2(num[j]) %KMOD;
			}
		}
	cout << ans%KMOD;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值