【双指针/二分】P1102 A-B 数对

P1102 A-B 数对

题目描述

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

输入格式

输入共两行。

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

第二行,第 iii 个数为 aia_iai,数字之间用一个空格隔开,共 NNN 个正整数,作为要求处理的那串数。

输出格式

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

输入输出样例 #1

输入 #1

复制代码
4 1
1 1 2 3

输出 #1

复制代码
3

说明/提示

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


暴力做法

先排序,然后再挨个遍历即可。

得分 76pts76pts76pts,时间超限。

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

bool cmp(int a,int b) {return a<b;}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n,c,answer=0;
	cin>>n>>c;
	int a[n];
	for(int i=0;i<n;i++)
		cin>>a[i];
	sort(a,a+n,cmp);
	for(int i=n-1;i>=0;i--) {
		for(int j=i-1;j>=0;j--) 
			if(a[i]-a[j]==c)
				++answer;
	}
	cout<<answer<<endl;
	return 0;
}

二分做法

lower_bound 和 upper_bound 的用法:

  • lower_bound:第一个 ≥\geq≥ val的位置;

  • upper_bound:第一个 >\gt> val的位置。
    查询某个值出现的次数:

    auto lo = lower_bound(a.begin(), a.end(), target);
    auto hi = upper_bound(a.begin(), a.end(), target);
    int count = hi - lo; // target 出现的次数

100pts,O(Nlog⁡N)100pts,O(N \log N)100pts,O(NlogN):

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

bool cmp(int a,int b) {return a<b;}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n,c,answer=0;
	cin>>n>>c;
	vector<int> a(n);
	for(int i=0;i<n;i++)
		cin>>a[i];
	sort(a.begin(),a.end(),cmp);
	
	for(int i=n-1;i>=0;i--) {
		if(a[i]<c) break;
		int val=a[i]-c;
		auto l=lower_bound(a.begin(),a.end(),val);
		auto r=upper_bound(a.begin(),a.end(),val);
		answer+=(r-l);
	}
	cout<<answer<<endl;
	return 0;
}

双指针做法

100pts,O(Nlog⁡N)100pts,O(N \log N)100pts,O(NlogN):

思路与二分做法相同。

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n, c, answer = 0;
    cin >> n >> c;
    vector<int> a(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];
    sort(a.begin(), a.end());
    
    int l = 0, r = 0;
    for (int i = 0; i < n; i++) {
        int target = a[i] - c;        while (l < n && a[l] < target) l++;
        while (r < n && a[r] <= target) r++;
        answer += r - l;
    }
    cout << answer << endl;
    return 0;
}
相关推荐
电梯界知识分子1 小时前
江西抚州临川九尊府五层别墅:受限楼梯间里,全黑铝合金观光井道配曳引龙门架的落地记录
大数据·前端·网络·算法·家用电梯
雪落漂泊1 小时前
C++智能指针
开发语言·jvm·c++
木井巳1 小时前
【记忆化搜索】斐波那契数
java·算法·leetcode·深度优先·剪枝·推荐算法
落魄大学生之流水线上谋生计1 小时前
JVM内存结构、垃圾回收算法与类加载机制详解
jvm·算法
. . . . .1 小时前
comfyUI原理
人工智能·算法·机器学习
淡海水1 小时前
10-05-高级-模式匹配-CSharp如何改变与数据结构的交互方式
数据结构·算法·c#·模式匹配
果壳science2 小时前
张祥前统一场论研讨会在香港理工大学举办
人工智能·算法
bnmoel2 小时前
C++ 基础入门篇(二):引用
开发语言·c++·引用·底层
richard_yuu2 小时前
AOI 实战第六篇:.onnx 到 C++ 的最后一公里
c++·深度学习·yolo