题目描述
金闪闪死后,红A拿到了王之财宝,里面有n个武器,长度各不相同。红A发现,拿其中三件武器首尾相接,组成一个三角形,进行召唤仪式,就可以召唤出一个山寨金闪闪。(例如,三件武器长度为10、15、20,可以召唤成功。若长度为10、11、30,首尾相接无法组成三角形,召唤失败。)红A于是开了一个金闪闪专卖店。他把王之财宝排成一排,每个客人会随机抽取到一个区间[l,r],客人可以选取区间里的三件武器进行召唤(客人都很聪慧,如果能找出来合适的武器,一定不会放过)。召唤结束后,客人要把武器原样放回去。m个客人光顾以后,红A害怕过多的金闪闪愉悦太多男人,于是找到了你,希望你帮他统计出有多少山寨金闪闪被召唤出来。
输入描述
第一行武器数量:n <= 110^7
第二行空格分隔的n个int,表示每件武器的长度。
第三行顾客数量:m <= 110^6
后面m行,每行两个int l,r,表示每个客人被分配到的区间。(l<r)
解题思路
三个数中,较小的那两个的和大于第三个就一定可以构成三角形,因此,对于[l,r]区间的数来说,只要找到这样的三个数就可以,为了减少运算,可以将其排序,然后从前到后每三个为一组进行比较,比如x1,x2,x3,x4,x1,x2,x3无法构成之后,可以直接进行x2,x3,x4的比较,x1不需要再参与计算中。这样的事件复杂度为O(NlongN),由于N可以达到10^7,所以直接暴力搜索一定会超时。
因为数据越多越容易构成三角形,边界情况就是两边之和等于第三边,a+b=c,那么如果去构造这样一个刚好找不到三角形的序列,则是1,1,2,3,5,,,Fibonacci数列,这个数列在int的表示范围内大概到46项,那么也就是说,当数量超过46的时候一定可以构成三角形(超过46一定会存在一个数字x,不属于Fibonacci数,可以插在满足fi-1<x<fi,因为fi-1+fi-2=fi,那么fi-1+fi-2>x,所以一定存在三角形)。
这样之需要对数量小于46的序列进行查找就可以了,大大减少了数据量。
实现代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int n,m,i;
cin>>n;
vector<int> data(n+1,0);
for(i=1;i<=n;i++)
cin>>data[i];
cin>>m;
int l,r,cnt=0;
for(i=0;i<m;i++){
cin>>l>>r;
if(r-l<2)
continue;
else if(r-l>=46)
cnt++;
else{
vector<int> v;
for(int j=l;j<=r;j++)
v.push_back(data[j]);
sort(v.begin(),v.end());
for(int j=0;j<v.size()-2;j++)
if(v[j]+v[j+1]>v[j+2]){
cnt++;
break;
}
}
}
cout<<cnt<<endl;
return 0;
}