ICPC Southeast USA 2020 Regional Contest Problem N Triangular Collection

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;
}
上一篇:03.数据库系统


下一篇:全新开发者体验实验室功能介绍