题目背景
上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来。
题目描述
有 n 根木棒,现在从中选 44 根,想要组成一个正三角形,问有几种选法?
答案对 10^9+7 取模。
输入格式
第一行一个整数 n。
第二行 n 个整数,第 i 个整数 ai 代表第 i 根木棒的长度。
输出格式
一行一个整数代表答案。
输入输出样例
输入 #1
4
1 1 2 2
输出 #1
1
分析
考察组合数的做法,(一)比如 1 1 2 2是符合题目要求的,那么选择的方法等于从(长度为 2 的木棒中选择两个方法数)乘(从长度为 1 的木棒中选择两个的方法数),(二)1 2 3 3 ,则为(从长度为3的木棒选择两个)乘(从长度为1的木棒选择一个)乘(从长度为 2 的木棒选择一个)。
设长度为 a b c d 。观察可以得出,符合要求的木棒一定满足 设长度为 a b c d 则a = b = c + d
其中c = d 或者c!=d 有分为两种情况,分别对应上面的(一)和(二)。
那么,用同储存木棒的长度,每次固定一个a/b,枚举c/d ,则d/c = a/b - c/d。分两种情况继续讨论
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define mod 1000000007
typedef long long ll;
ll sum = 0;;
int a, b ,c ,d;
int arr[5005];
ll c1(ll x)
{
return x;//组合数的公式
}
ll c2(ll y)
{
return (y * (y - 1)) / 2;//从长度一样的木棒里面选两个的组合数公式
}
int main(void)
{
int n;
scanf_s("%d", &n);
for (int i = 1; i <=n ; i++)
{
scanf_s("%d", &a);
arr[a]++;//桶记录木棒的长度
}
for (int i = 2; i <= 5000; i++)//长度为2开始,长度为1不可能满足(a)的选取
{
for (int j = 1; j <= i / 2; j++)//J最多只能是i的一半
{
b = i - j;
if (b == j)
{ //因为a=b则符合i(a/b)长度的木棒至少有两个
if (arr[i] >= 2 && arr[j] >= 2)
{
sum = (c2(arr[i]) * c2(arr[j]) % mod) + sum;
}//从长度为i的木棒中选择两个 从长度为 j 的木棒里选择两个
}
else if (b != j)
{
if (arr[i] >= 2 && arr[j] >= 1 && arr[b] >= 1)
{//从长度为i的木棒中选择两个 从长度为 j 的木棒里选择一个
sum = (c2(arr[i]) * c1(arr[j])*c1(arr[b]) % mod) + sum; //从长度b的木棒里面选一个
}
}
sum %= mod;
}
}
cout << sum % mod << endl;
return 0;
}