洛谷P1102 A-B 数对

题目描述

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

输入格式

输入共两行。

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

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

输出格式

一行,表示该串正整数中包含的满足 AB=C 的数对的个数。

输入输出样例

输入

4 1

1 1 2 3

输出

3

说明/提示

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

对于 100% 的数据,1≤N≤2×10^5,0≤ai<2^30,1≤C<2^30。

题解

整体思路:

已知C,那么遍历每一个数,对每一个数B寻找是否有符合A=B+C的A存在。

相当于BC已知,找A.

直接使用二分的困难:

当出现连续相等且满足条件的数列时,不能同时找到连续相等数列的左端和右端。

解决方法:

使用两次二分,一次找到满足条件的数列的左端,一次找到右端。两端位置序号相减,即可找到此时B情况下A出现的次数。

# 数据读入
n,c = map(int,input().split())
num = list(map(int,input().split()))
num.sort()    #对读入数列进行排序

res = 0    # 存放满足条件的次数

# 定义一个函数check,寻找每一个B的情况下满足条件的A的个数
def check(i):
    # 考虑会出现[....3,3,3,3....]的连续情况,需要分别找到满足条件的连续相等的数列的两端
    
    # 寻找满足条件的最左边的A的位置
    L = i    # 左端的位置
    R = n-1    # 右端的位置
    while L <= R:
        mid=(L+R)//2
        if num[mid] >= num[i]+c:    # 如果中间数比A大,说明满足要求的在左边
            R=mid-1    # 右边界移至中间偏左一个位置
        else:
            L=mid+1    # 否则左边界右移
    LPos = L    # 记录字串左边界

    # 寻找满足条件的最右边的A的位置
    L=i
    R=n-1
    while L<=R:
        mid=(L+R)//2
        if num[mid] > num[i]+c:
            R=mid-1
        else:
            L=mid+1
    RPos = R    # 记录字串右边界 

    return RPos-LPos+1    # 返回对当前B满足条件的A的个数


# 针对每一个B二分查找寻找满足的A的个数
for i in range(n):
    res+=check(i)

print(res)

你可能感兴趣的:(算法题解,python)