【题解】【算法】- 洛谷 - P3799 妖梦拼木棒(组合数学)

题目背景

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

题目描述

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

答案对 109 + 7 取模。

输入格式

第一行一个整数 n。

第二行 n 个整数,第 i 个整数 ai 代表第 i 根木棒的长度。

输出格式

一行一个整数代表答案。

输入输出样例

输入 #1复制

4 
1 1 2 2

输出 #1复制

1

说明/提示

数据规模与约定

  • 对于30% 的数据,保证 n ≤ 5 × 103
  • 对于 100% 的数据,保证 1 ≤ n ≤ 105,0 ≤ ai ≤ 5 × 103

思路

暴力即可,详解看代码

AC代码

#include 
#include 
#include 
#include 
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e5 + 5;
int n, maxj, t, res;
//sum数组存储的是不同长度的木棍的数量,下标是长度,大小是数量
int sum[N];
int main(void)
{
    cin >> n;
    for(int i = 0; i < n; i ++){
        //t相当于中间变量
        cin >> t;
        //类似桶排序存入数组中,简化问题
        sum[t] ++;
        //找到最长的那个木棍
        maxj = max(maxj, t);
    }
    //i从2开始即可,长度为1的木棍没意义,不可能分成两个木棍
    for(int i = 2; i <= maxj; i ++){
        //如果木棍数大于等于2,即可以有两个相等的木棍组成正三角形的两个边
        if(sum[i] >= 2){
            //找到另外一边的其中一根木棍,长度大于i / 2也没有什么意义,因为另外一根木棍可以通过i - j求得它的长度
            for(int j = 1; j <= i / 2; j ++){
                int k = i - j;
                //两根木棍长度一样
                if(k == j)
                    //类似排列组合,第三边两根长度一样的木棍,那么只需要在这种长度的木棍里选两根,组成另外两边的两根一种长度的木棍里选两根就可
                    res += (sum[k] * (sum[k] - 1) / 2 % mod)* (sum[i] * (sum[i] - 1) / 2 % mod);
                else
                    //类似排列组合,第三边的长度不一样的木棍,其中一种长度的木棍里选一根木棍,另一种长度的木棍里选一根木棍,组成另外两边的两根一种长度的木棍里选两根就可
                    res += (sum[k] % mod) * (sum[j] % mod) * (sum[i] * (sum[i] - 1) / 2 % mod);
                res %= mod;
            }
        }
    }
    cout << res << endl;
    return 0;
}

你可能感兴趣的:(算法)