题目描述
兔子军团凭借着独有的三角合击技能,成为了地表最强的军团。 免子军团共有 N 名士兵,每位士兵都有一把刃长为 Li 的佩剑,如果三位士兵的佩剑刃长能组成一个三角形,则说明其属性相符,则这三位士兵可以合力使出一次三角合击,击退敌军。 兔子军团的司令小喵正在检阅这支军团,他想知道,如果任意的三位士兵只能组合一次,军团能使出多少次三角合击?
输入格式
共两行: 第一行一个整数 N ,表示军团的士兵数量; 第二行 N 个整数瓜,依次表示第 i 位士兵佩剑的刃长。
输出格式
一行一个整数,输出三角合击的次数。
样例输入1
3
4 2 3
样例输出1
1
样例1解析
第 1,2,3 位士兵的佩剑组成边长为 {4,2,3} 的三角形,能使出 1 次三角合击。
样例输入2
7
218 786 704 233 645 728 389
样例输出2
23
数据范围
对于 40% 的数据: 3 ≤ N ≤ 100 ; 1 ≤ ≤ ; 对于 100% 的数据: 3 ≤ N ≤ 2 x ; 1 ≤ ≤
解法分析
枚举 + 二分查找:
朴素做法的时间复杂度为 ,观察数据范围显然不能通过。
根据三角形的形成规则来优化求解过程,枚举三角形的两边 和 ,显然第三边 的取值范围为 。二分找到区间的左端点 和右端点 ,特判一下小于 的情况,然后将贡献计入答案中。
输出时需注意除以 3 去掉重复方案,时间复杂度优化至 。
参考代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n, a, x, y, len,ans;
vector<int> l;
int main() {
cin >> n;
for(int i = 0; i < n; i++){
cin >> a;
l.push_back(a);
}
sort(l.begin(), l.end());
for(int i = 0; i < n;i++){
for(int j = i + 1; j < n; j++){
x = l[i], y = l[j];
auto st = upper_bound(l.begin(), l.end(), abs(x - y));
auto ed = lower_bound(l.begin(), l.end(), (x + y));
len = ed - st;
if(abs(x - y) < x) len--;
if(abs(x - y) < y) len--;
if(len > 0) ans += len;
}
}
ans /= 3;
cout << ans << endl;
return 0;
}