洛谷1102 A-B数对

题目描述

给出一串数以及一个数字 C,要求计算出所有 A - B = C 的数对的个数(不同位置的数字一样的数对算不同的数对)。


说明/提示

对于 75% 的数据, 1 ≤ N ≤ 2000 1 \leq N \leq 2000 1N2000

对于 100% 的数据, 1 ≤ N ≤ 2 × 1 0 5 1 \leq N \leq 2 \times 10^5 1N2×105

保证所有输入数据都在 32 位带符号整数范围内。


思路

虽然这道题是道水题,思路也比较简单(虽然我还是没想出来),但这道题很好的体现了hash表的用途——查询。

将每个数读入后对一个质数取模,按照余数的不同进行分类,以余数作为下标,将每个数存入hash表中。

如果两个数有相同的余数怎么办?一般更高效的方法是以每个余数为表头建立邻接表,但Oi里不推荐使用动态内存,可以用这种方法代替:以余数为起点,将整个hash表遍历一遍,找到空位就放下。

将每个数都放入hash表中后,枚举每个数,将其作为式子A-B=C中的A(我对减法生来不爽,就用的是B),式子移项后可得A-C=B,其中A、C已知。这时将在hash表中查询A-C的值,若存在,则说明存在满足式子A-B=C的值B。


代码

(代码没敲注释,但每个函数名的使用都比较规范,一看应该就知道功能,英语不好的百度一下就知道了)

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll P=1000003;
struct node
{
    
    
	ll val,sum;
}hash[P];
ll n,c,s[P],ans;
ll key(ll x){
    
    return x%P;}
ll locate(ll x)
{
    
    
	ll orig=key(x);
	ll i=0;
	while(i<P&&hash[(orig+i)%P].val!=x&&hash[(orig+i)%P].val) i++;
	return (orig+i)%P;
}
void insert(ll x)
{
    
    
	ll pos=locate(x);
	if(hash[pos].val==x) hash[pos].sum++;
	else if(!hash[pos].val) hash[pos].val=x,hash[pos].sum++;
}
ll query(ll x)
{
    
    
	ll pos=locate(x);
	if(hash[pos].val==x) return hash[pos].sum;
	else return 0;
}
int main()
{
    
    
	scanf("%lld%lld",&n,&c);
	for(int i=1;i<=n;i++)
	{
    
    
		scanf("%lld",&s[i]);
		insert(s[i]);
	}
	for(int i=1;i<=n;i++)
	ans+=query(s[i]+c);
	printf("%lld",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45383207/article/details/113138765
A-B