AT5252题解
题目解释
从 \(a\) 数组中找到 \(a_i\)、\(a_j\)、\(a_k\),满足
\(\begin{cases}a_i+a_j=a_k\\a_i+a_k=a_j\\a_j+a_k=a_i \end{cases}\)
中的任意一条。
前置芝士:lower_bound
lower_bound 是 C++ 自带的二分函数,时间复杂度 \(\mathcal O (\log n)\),食用方法是:
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\)。
思路 1
直接暴力枚举 \(i\)、\(j\)、\(k\),但由于 \(n \le 2\times10^3\),时间复杂度 \(\mathcal O (n^3)\),必定超时。
思路 2
先对数组 \(a\) 排序,然后枚举 \(i\)、\(j\),然后在 \([ j+1,n)\) 找到最后一个 \(<i+j\) 的,再将 \(ans+\text{那个数的位置} - 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\) 的这一段,具有单调性。
所以二分就行。
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\),\(j<n-1\)。

浙公网安备 33010602011771号