【CF1324D】Pair of Topics

  题意:给定一个长度为 $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 \neq j$ 时,$(i,j)$ 和 $(j,i)$ 肯定有一个不满足 $i<j$,所以统计出来的答案有 恰好一半 是不满足 $i<j$ 的,要除以 $2$。

  时间复杂度 $O(n\; \log\; n)$。


  在统计的时候,我们发现统计到的 $j$ 没有满足 $j \neq 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\n", ans >> 1);        // 答案要除以 2

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zengpeichen/p/12484976.html