20191103 专题:哈希表

总览:

用来快速查询一个数/值/状态…
其实我也不是很了解

T1 P1102 A-B 数对

P1102 A-B 数对
题目描述
出题是一件痛苦的事情!
题目看多了也有审美疲劳,于是我舍弃了大家所熟悉的 A + B P r o b l e m A+B Problem A+BProblem,改用 A − B A-B AB 了哈哈!
好吧,题目是这样的:给出一串数以及一个数字 C C C,要求计算出所有 A − B = C A-B=C AB=C 的数对的个数。(不同位置的数字一样的数对算不同的数对)

输入格式
第一行包括 2 2 2个非负整数 N N N C C C,中间用空格隔开。

第二行有 N N N个整数,中间用空格隔开,作为要求处理的那串数。

输出格式
输出一行,表示该串数中包含的所有满足 A − B = C A−B=C AB=C的数对的个数。

输入输出样例
输入
4 1
1 1 2 3
输出
3
说明/提示
对于73%的数据, N ≤ 2000 N ≤ 2000 N \le 2000N≤2000 N2000N2000
对于100%的数据, N ≤ 200000 N ≤ 200000 N \le 200000N≤200000 N200000N200000
所有输入数据都在 l o n g i n t longint longint范围内。

思路:
A − B = C 即 B + C = A A-B=C即B+C=A AB=CB+C=A
统计每个数出现的个数,再查询累加。
注意:这道题是我做的第一道 h a s h t a b l e hash table hashtable的题,但是它tm h a s h hash hash
解决方法…看代码!

代码:

#include<bits/stdc++.h>
using namespace std;
#define in Read()

long long in{
	long long s=0,f=1;char x;
	for(x=getchar();!isdigit(x);x=getchar())    if(x=='-')  f=-1;
	for( ;isdigit(x);x=getchar())   s=(s<<1)+(s<<3)+(x&15);
	return s*f;
}

const int A=4e6+5;
const int mod=1e6+19;
const int add=23;
int n,c;
struct hash{
	int num,x;
}h[A];
int s[A];
long long ans;

inline int hash(int x){
	return abs(x%mod+add);
}

inline void putin(int a){
	int x=hash(a);
	while(h[x].x!=a&&h[x].x!=0)    x=hash(x);
	h[x].num++,h[x].x=a;
	return;
}

inline int find(int a){
	int x=hash(a);
	while(h[x].x!=a&&h[x].x!=0) x=hash(x);
	return h[x].num;
}

signed main(){
	n=in,c=in;
	for(int i=1;i<=n;i++){
		s[i]=in;
		putin(s[i]);
	}
	for(int i=1;i<=n;i++)
		ans+=find(s[i]+c);
	printf("%lld",ans);
	return 0;
}

T2 P4305 [JLOI2011]不重复数字

P4305 [JLOI2011]不重复数字
题目描述
给出 N N N个数,要求把其中重复的去掉,只保留第一次出现的数。
例如,给出的数为 1218331923654 1 2 18 3 3 19 2 3 6 5 4 1218331923654,其中 2 2 2 3 3 3有重复,去除后的结果为 1218319654 1 2 18 3 19 6 5 4 1218319654

输入格式
输入第一行为正整数 T T T,表示有 T T T组数据。
接下来每组数据包括两行,第一行为正整数 N N N,表示有 N N N个数。第二行为要去重的 N N N个正整数。

输出格式
对于每组数据,输出一行,为去重后剩下的数字,数字之间用一个空格隔开。

输入输出样例
输入
2
11
1 2 18 3 3 19 2 3 6 5 4
6
1 2 3 4 5 6
输出
1 2 18 3 19 6 5 4
1 2 3 4 5 6
说明/提示
对于100%的数据, 1 ≤ N ≤ 50000 , 给 出 的 数 在 32 位 有 符 号 整 数 范 围 内 。 T ≤ 50 。 1 \le N \le 50000,给出的数在32位有符号整数范围内。T \le 50。 1N5000032T50

思路:
h a s h t a b l e hashtable hashtable判断数是否出现过

代码:

#include<bits/stdc++.h>
using namespace std;
#define in Read()

long long in{
	long long s=0,f=1;char x;
	for(x=getchar();!isdigit(x);x=getchar())    if(x=='-')  f=-1;
	for( ;isdigit(x);x=getchar())   s=(s<<1)+(s<<3)+(x&15);
	return s*f;
}

const int A=5e5+5;
const int B=2e6+5;
const int mod=1e6+103;
int t;
int n;
long long a[A],r[A],num;
long long head[B],tot;
struct hash_table{
	long long nex,val;
}vec[B];

inline long long hash(long long x){
	return abs(x%mod+23);
}

inline void putin(long long x){
	long long w=hash(x);
	vec[++tot]={head[w],x};head[w]=tot;
}

inline bool find(long long x){
	long long w=hash(x);
	for(int y=head[w];y;y=vec[y].nex){
		long long z=vec[y].val;
		if(z==x)    return true;
	}
	return false;
}

inline void clean(){
	num=0,tot=0;
	memset(head,0,sizeof(head));
}

signed main(){
	t=in;
	while(t--){
		clean();
		n=in;
		for(int i=1;i<=n;i++)
			a[i]=in;
		for(int i=1;i<=n;i++){
			if(!find(a[i])) r[++num]=a[i];
			putin(a[i]);
		}
		for(int i=1;i<=num;i++)
			printf("%lld ",r[i]);
		printf("\n");
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值