刚开始我想到了一个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;
}