题意:给定一个长度为 $n$ 的序列,求出满足 $1 le i<j le n$ 且 $a_i+a_j>b_i+b_j$ 的 $(i,j)$ 对数。
我们把 $a_i+a_j>b_i+b_j$ 变形,变成 $(a_i-b_i)+(a_j-b_j)>0$。
令 $c_i=a_i-b_i;(1 le i le n)$,那么要求就只有 $c_i+c_j>0$ 了。
对于 $1$ 到 $n$ 中每一个 $i$,我们都找到满足 $c_j>-c_i$ 的 $j$ 的个数,并加起来统计,这可以用 排序 + STL 或 二分 解决。
因为对于 $i eq j$ 时,$(i,j)$ 和 $(j,i)$ 肯定有一个不满足 $i<j$,所以统计出来的答案有 恰好一半 是不满足 $i<j$ 的,要除以 $2$。
时间复杂度 $O(n; log; n)$。
在统计的时候,我们发现统计到的 $j$ 没有满足 $j eq i$。
如果当前的 $i$ 满足 $2c_i>0$,即 $c_i>0$ 时,自己肯定会被统计到。
所以答案是统计的值减去满足 $c_i>0$ 的 $i$ 的个数,再除以 $2$。
参考代码:
#include <algorithm> #include <cstdio> #define INF 1e9 #define eps 1e-6 typedef long long ll; int n, a[200010], b[200010], k; ll ans; // 注意开 long long int main(){ scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1, x; i <= n; i++) scanf("%d", &x), a[i] -= x; // 此处 a_i 就等同于上面的 c_i std::sort(a + 1, a + n + 1); for(int i = 1; i <= n; i++){ k = std::upper_bound(a + 1, a + n + 1, -a[i]) - a; // 上面求的是第一个大于 -a_i 的数字的位置 if(a[i] > 0) ans--; // 特判 a_i > 0 的情况 ans += (ll)n - k + 1; } printf("%lld ", ans >> 1); // 答案要除以 2 return 0; }