【双指针/二分】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;
}
相关推荐
I_belong_to_jesus10 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Rabitebla12 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
码客-ygluu17 小时前
一个通用游戏数据服务器
c++·架构
another heaven17 小时前
【C/C++ Ranges 是零开销抽象吗?拆开管道、惰性求值和编译期膨胀】
c语言·开发语言·c++
Code_Solitude17 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司18 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
YLCHUP20 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
xiaoye-duck20 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型
思麟呀20 小时前
背包DP(01背包+完全背包)
c++·算法