P1102 A-B 数对

题目传送门

题目描述

题目描述

出题是一件痛苦的事情!

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

好吧,题目是这样的:给出一串数以及一个数字 CC,要求计算出所有 A - B = CAB=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式

输入共两行。

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

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

输出格式

一行,表示该串数中包含的满足 A - B = CAB=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。

保证所有输入数据绝对值小于 2^{30}230,且 C \ge 1C≥1。

2017/4/29 新添数据两组

算法求解

分析

  • 首先对给的数组a排序

  • 然后用b数组记录每个数字及其出现次数(也是按照数字大小排序的)

  • 遍历每种数字,对每种数字x,自己的数量是num1,二分查找b中有没有 x + c这个数字,有的话返回其数量num2,没有返回-1

  • 那么如果存在x+c,且其数量为num2,则这两种数组成的数对数量为num1 * num2

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int N = 200010;
int a[N];
vector<PII> b;
int n, c;
int find(int x)
{
	int l = 0, r = b.size();
	while(l < r)
	{
		int mid = (r + l) >> 1;
		if(b[mid].first >= x) r = mid;
		else					   l = mid+1;
	}
	if(b[l].first != x) return -1;
	else			    return b[l].second;
} 

int main()
{
	scanf("%d%d", &n, &c);
	for(int i = 0; i < n; i++)
	{
		scanf("%d", &a[i]);
	}
	
	sort(a, a + n);
	
	int cnt = 0;	
	for(int i = 0; i < n; i++)
	{
		
		if(i && a[i] != a[i-1])
		{
			b.push_back({a[i-1], cnt});
			cnt = 0;
		}
		cnt++;
	}
	b.push_back({a[n-1], cnt});
	
//	for(int i = 0; i < b.size(); i++)
//		printf("%d %d\n", b[i].first, b[i].second);

	LL res = 0;
	for(int i = 0; i < b.size(); i++)
	{
		int t1 = b[i].first;
		int num1 = b[i].second;
		
		int t2 = find(t1 + c);
		if(t2 != -1)
		{
			res += (LL)t2 * num1;
		}
	}
	cout << res;
	
	return 0;
}

时间复杂度

\(O(nlogn)\)

参考文章

posted @ 2022-03-04 09:22  VanHope  阅读(42)  评论(0编辑  收藏  举报