题目背景
上道题中,小 Y 斩了一地的木棒,现在她想要将木棒拼起来。
题目描述
有 n 根木棒,现在从中选 4 根,想要组成一个正三角形,问有几种选法?
答案对 109+7 取模。
输入格式
第一行一个整数 n。
第二行往下 n 行,每行 1 个整数,第 i 个整数 ai 代表第 i 根木棒的长度。
输出格式
一行一个整数代表答案。
输入输出样例
输入 #1复制
4 1 1 2 2
输出 #1复制
1
说明/提示
数据规模与约定
- 对于 30% 的数据,保证 n≤5×103。
- 对于 100% 的数据,保证 1≤n≤105,1≤ai≤5×103
卡了好长时间终于AC了呜呜呜。
题目分析
这道题不能使用dfs枚举每一种情况会超时,别问我怎么知道的。
改变思路,我们侧重于题目本身进行分析。要想利用4个木棒得到一个正三角形,首先得有两个相同的木棒,并且这个长度的木棒会比另外两个木棒的长度长。我们合理使用数组来存储每个长度木棒的数量,将数组a开到满足题目的最大值。
从大到小进行遍历,如果它的值a[i]大于等于2,则在1到i/2的范围内寻找满足题目情况的值。
这里使用到的还是重要的组合公式。两种物品分别有m和n个,每种里面都选择一种,则有m * n种组合。
这里给出一种关于没有顺序的cnm的计算代码(边乘边除法):
ll C(ll n, ll m) {ll ans = 1;for (ll i = 1; i <= m; i++) {ans = ans * (n - m + i) / i;}return ans;
}
对于m == 2的情况我们直接可以返回n * (n - 1) / 2;
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7;
int n, a[5005] = {0};int zuhe(int m){if (m < 2) return 0;return (ll)m * (m - 1) / 2 % mod;;
}
int main()
{ll sum = 0;cin >> n;int tmp;for (int i = 0; i < n; i++){cin >> tmp;a[tmp]++;}for(int i = 5001; i > 1; i--){if(a[i] <= 1)continue;else{// >= 2int cm2 = zuhe(a[i]);for(int j = 1; j <= i / 2; j++){//找匹配的数子if(j != i - j){if(a[j] > 0 && a[i - j] > 0){//可以相加的两个数都是大于0的sum += a[j] * a[i - j] * cm2 % mod;sum %= mod;}}else{// j == i - jif(a[j] > 1)sum += zuhe(a[j]) * cm2 % mod;sum %= mod;}}}sum %= mod;}cout << sum%mod;
}