题目描述
给出一串数以及一个数字 C,要求计算出所有 A - B = C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
说明/提示
对于 75% 的数据, 1 ≤ N ≤ 2000 1 \leq N \leq 2000 1≤N≤2000
对于 100% 的数据, 1 ≤ N ≤ 2 × 1 0 5 1 \leq N \leq 2 \times 10^5 1≤N≤2×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;
}