注意:这篇题解写给萌新看的,非常详细哦QaQo( ̄▽ ̄)ブ。
题目解释
从 a a a 数组中中找到 a i a_i ai、 a j a_j aj、 a k a_k ak,满足
{ a i + a j = a k a i + a k = a j a j + a k = a i \begin{cases}a_i+a_j=a_k\\a_i+a_k=a_j\\a_j+a_k=a_i \end{cases} ⎩⎪⎨⎪⎧ai+aj=akai+ak=ajaj+ak=ai
中的任意一条。
前置芝士:lower_bound
lower_bound 是c++自带的二分的函数,时间复杂度 O ( log n ) \mathcal O (\log n) O(logn)(不用说),食用方法是
lower_bound(一个指针,另一个指针,a)
其中这两个指针都在同一个数组里,
它的用处是在第一个指针所指向的数(包括)到第二个指针之间所指向的数中(不包括)第一个大于 n 的数,这两个指针之间的子序列必须是单调不下降的,并返回这个数的地址。
使用示例:
int a[]={1,2,3,4,5,6,9,10,1000};
cout<<lower_bound(a,a+n,3)-a;//会输出2
拓展:关于指针
对于一个数组 a,a[0] 的地址可以表达为 a,即
int a[100];
cout<<&a;
会输出 a[0] 的地址。
而且数组的地址是连续的,所以 a[i] 的地址可以表达为 a+i。
思路
solution 1
直接暴力枚举 i i i、 j j j、 k k k,但由于 n ≤ 2 × 1 0 3 n \le 2\times10^3 n≤2×103,时间复杂度 O ( n 3 ) \mathcal O (n^3) O(n3),必定超时。
solution 2
先对数组 a 排序,然后枚举 i i i、 j j j,然后在 [ j + 1 , n ) [ j+1,n) [j+1,n) 找到最后一个 < i + j < i+j <i+j 的,再将 a n s ans ans 加上(那个数的位置 - j + 1),具体看下面:
1 2 3 4 5 6 7 10 12 15 17
0 0 0 0 i j Y Y N N N
我们观察 > j > j >j 的这一段,具有单调性。
所以二分就行。
code
sort(a,a+n);
for(int i=0;i<n-2;i++){
for(int j=i+1;j<n-1;j++){
int k=lower_bound(a+j+1,a+n,a[i]+a[j])-a;
ans+=(k-j-1);
}
}
cout<<ans;
注意&提示:
- 数组开大一点;
- lower_bound 第一个参数是 a+j+1;
- 循环范围: i < n − 2 i<n-2 i<n−2, j < n − 1 j<n-1 j<n−1。
the end