题:A-B 数对(二分)

A-B 数对 - 洛谷

题目背景

出题是一件痛苦的事情!

相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!

题目描述

给出一串正整数数列以及一个正整数 CC,要求计算出所有满足 A - B = CA−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式

输入共两行。

第一行,两个正整数 N,CN,C。

第二行,NN 个正整数,作为要求处理的那串数。

输出格式

一行,表示该串正整数中包含的满足 A - B = CA−B=C 的数对的个数。

输入输出样例

输入 #1复制

4 1
1 1 2 3

输出 #1复制

3

说明/提示

对于 75\%75% 的数据,1 \leq N \leq 20001≤N≤2000。

对于 100\%100% 的数据,1 \leq N \leq 2 \times 10^51≤N≤2×105,0 \leq a_i <2^{30}0≤ai​<230,1 \leq C < 2^{30}1≤C<230。

2017/4/29 新添数据两组

题解:

这道题可以说是二分的裸题了,今天做的时候顺便回顾一下二分的细节,有些遗忘了。

思路:

要求计算出所有满足 A - B = C 的数对的个数。c已知,找A和B满足A-B=C,即枚举A,对于不同的A,找到B满足B=A-C即可。

对于不同的A,B的个数可能有0、1、多个:排序后二分查找数组中第一个B出现的位置,若二分答案与B不等,则无答案;若二分答案与B相等,则继续二分查找最后一个B出现的位置,得到左右边界,答案+=B的个数即可。

 

降序排列

二分找左边界:

 左边界满足:l的右侧都小于等于x,也就是说,若f[mid]<=x,则答案区间在mid左侧

while(l<r){
    int mid = l + r >> 1;
    if(f[mid]<=x) r = mid;
    else l = mid+1;
}

 二分找右边界:

右边界满足:l的左侧都大于等于x,也就是说,若f[mid]>=x,则答案区间在mid右侧

int ll = l;
r = n-1;
while(ll<r){
    int mid = ll+r+1>>1;
    if(f[mid]>=x) ll = mid;
    else r = mid - 1;
}

 完整代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;

const int N = 2e5+10;

int f[N];

int main(){
    int n, c;
    cin>>n>>c;
    for(int i=0;i<n;i++) scanf("%d",&f[i]);
    
    LL ans = 0;
    sort(f,f+n,greater<int>());
    
    for(int i=0;i<n-1;i++){
        int x = f[i]-c;
        if(x<0) break;
        int l = i, r = n-1;
        while(l<r){
            int mid = l + r >> 1;
            if(f[mid]<=x) r = mid;
            else l = mid+1;
        }
        if(f[l]==x){
            ans++;
            int ll = l;
            r = n-1;
            while(ll<r){
                int mid = ll+r+1>>1;
                if(f[mid]>=x) ll = mid;
                else r = mid - 1;
            }
            ans+=r-l;
        }
    }
    
    cout<<ans<<endl;
    
    
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值