N Triangular Collection
Call a set of positive integers triangular if it has size at least three and, for all triples of distinct integers from the set, a triangle with those three integers as side lengths can be constructed.
Given a set of positive integers, compute the number of its triangular subsets
Input
The first line of input contains a single integer n (1 ≤ n ≤ 50), which is the number of integers inthe set.
Each of the the next n lines contains a single integer x (1 ≤ x ≤ 10^9 ). These are the elements ofthe set. They are guaranteed to be distinct.
Output
Output a single integer, which is the number of triangular subsets of the given set.
Sample Input 1
5
3
1
5
9
10
Sample Output 1
2
Sample Input 2
10
27
26
17
10
2
14
1
12
23
39
Sample Output 2
58
题目大意:
如果一个集合中选择任意三条边都可以组成一个三角形,那么这个集合就叫做三角形集合。
给出一些边长,求其中三角形集合的个数。
题解:
如果我们暴力枚举,那么时间复杂度为O(n^3),这里的数据量有10e9,一定会超时,我们可以求出满足题意的大集合来推出小集合的个数。
我们可以先将三角形的边长从小到大排序,然后枚举三角形的前两条边,确定两条边后第三条边可以从数组末尾开始找:
while (a[i] + a[j] <= a[pos]) pos --; // 找到满足条件的集合,则这个集合所有的子集都满足条件
一旦找到第三条边,因为数组是递增的,那么第三条边到第二条边之间的所有边都满足题意。
确定了一个集合后那么这个集合的子集有2^n - 1个,每次累加所有的子集就可以得出答案。
res += (1ll << (pos - j)) - 1; // 集合的子集个数为2^n - 1
AC代码:
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
ll a[N];
int main() {
ll n;
cin >> n;
for (ll i = 0; i < n; i ++) cin >> a[i];
sort(a, a + n); // 将边长从小到大排序
ll res = 0;
for (int i = 0; i < n; i ++) {
for (int j = i + 1; j < n; j ++) { // 枚举两条边的起点和终点
ll pos = n - 1;
while (a[i] + a[j] <= a[pos]) pos --; // 找到满足条件的集合,则这个集合所有的子集都满足条件
res += (1ll << (pos - j)) - 1; // 集合的子集个数为2^n - 1
}
}
cout << res << '\n';
return 0;
}