【双指针/二分】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;
}
相关推荐
Demon--hx7 小时前
C++ 文件流:理解 ifstream/ofstream 与 RAII 机制
开发语言·c++
纪念 2297 小时前
C++ stack和queue
开发语言·c++
CodeYp20197 小时前
第6讲:模板初阶
开发语言·c++·模板
吞下星星的少年·-·7 小时前
牛客周赛 119B题(贪心)
算法·贪心
.YM.Z7 小时前
【C++11】初识——右值引用和移动语义,可变参数模板
c++·c++11
NEFU_Jyj7 小时前
牛客周赛R166(max型瓶颈最短路,前后缀DP合并)
算法·深度优先
要练八块腹肌8 小时前
红黑树的实现以及对map和set的封装
c++
Tisfy8 小时前
LeetCode 3644.排序排列:不对则与(脑筋急转弯)
数据结构·算法·leetcode·题解·位运算
骑着蜗牛撵大象3278 小时前
从三次握手到 epoll:C++ 写出可落地的 TCP Socket 服务端
网络·c++·tcp/ip·高并发·tcp·epoll
卡卡~~8 小时前
C++学习
开发语言·c++