题目描述
传送门
出题是一件痛苦的事情!
相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
好吧,题目是这样的:给出一串数以及一个数字 C,要求计算出所有 A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个整数 N,C。
第二行,N 个整数,作为要求处理的那串数。
输出格式
一行,表示该串数中包含的满足 A−B=C的数对的个数。
输入输出样例
输入 #1
4 1
1 1 2 3
输出 #1
3
说明/提示
对于 75%的数据,1≤N≤2000
对于 100% 的数据,1≤N≤2×10^51
保证所有输入数据都在 32 位带符号整数范围内。
2017/4/29 新添数据两组
解题思路
–
HASH表
统计一个数列一个数出现的次数,最简单粗暴的方法是桶排
但是如果数列的数很大,但其实数字数量不大,桶排就很难应用
HASH表的思想就是通过一种方法,比如取模,重建散列
比较简单的方法就是取模,以所有数字的取模数桶排,如果当前下标已有数,就往后排
–
N^2明显不行
将数列重建hash表,同时建立桶排
枚举桶排数列,在hash表中查找B,再通过“B+C=A”来确定A
如果A和B都存在,那么公式成立,答案 += “A”的数量 x “B”的数量
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int F=1000007;
long long n,m,a[1000200],b[1000200],t;
long long ha[F][2],ans;
int hash(long long x){
int cnt=x%F,i=0;
while(i<F&&ha[(cnt+i)%F][1]&&ha[(cnt+i)%F][0]!=x)//如果当前位有数
i++;//往后排
return (cnt+i)%F;
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
int x=hash(a[i]);//存进hash表
if(!ha[x][0]){
ha[x][0]=a[i];
b[++t]=x;//桶排
}
ha[x][1]++;//统计数量
}
for(int i=1;i<=t;i++){
int x=hash(ha[b[i]][0]+m);//查找B
if(ha[b[i]][0]+m==ha[x][0])//B+C=A
ans+=ha[x][1]*ha[b[i]][1];
}
printf("%lld",ans);
}