BZOJ 2761 不重复的数字 哈希 or set or 二叉搜索树
这是我第一次写哈希,感觉还好。虽然这道题今天一直在想用什么方法最好,一开始想过用 unique 这个函数, 想过 map ,想过 set,(刚才看别人题解的过程中,也有用treap写的,其实就是二叉搜索树) 但是map 和 set 查询都是 log n的,太慢了点。而且,我一直想学哈希,之所以一直没怎么学(只看了理论,没写过),有一个原因也是看过的哈希的代码太少(印象中只有紫书中的一篇和下文代码类似的,还有白书中基于哈希值的LCP),自己不好把握(这一次写,第一次交,就因为负数的问题,RE),最后就把他拿来做为 哈希 的第一道题了,加油,这是我朝哈希迈出的第一步。
这是set的代码,一开始我还不知道set中怎么查询有没有一个值的存在。最后百度了才知道,唉,要加油啊!傻逼!(这份代码跑了700多毫秒)
1 #include<cstdio> 2 #include<iostream> 3 #include<set> 4 #define rep(i,j,k) for(int i = j; i <= k; i++) 5 #define maxn 50005 6 using namespace std; 7 8 set<int> s; 9 int read() 10 { 11 int s = 0, t = 1; char c = getchar(); 12 while( !isdigit(c) ){ 13 if( c == '-' ) t = -1; c = getchar(); 14 } 15 while( isdigit(c) ){ 16 s = s * 10 + c - '0'; c = getchar(); 17 } 18 return s * t; 19 } 20 21 int main() 22 { 23 int t = read(); 24 while( t-- ){ 25 s.clear(); 26 int n = read(); 27 bool first = 1; 28 rep(i,1,n){ 29 int x = read(); 30 if( !s.count(x) ){ 31 if( first ) { 32 printf("%d", x); 33 first = 0; 34 } 35 else printf(" %d", x); 36 s.insert(x); 37 } 38 } 39 printf("\n"); 40 } 41 return 0; 42 }
这是哈希的代码,只跑了480毫秒
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define rep(i,j,k) for(int i = j; i <= k; i++) 5 #define maxn 100003 6 #define mod 100003 7 using namespace std; 8 9 int head[maxn] = {0}, next[maxn] = {0}; 10 int num[maxn] = {0}; 11 12 int read() 13 { 14 int s = 0, t = 1; char c = getchar(); 15 while( !isdigit(c) ){ 16 if( c == '-' ) t = -1; c = getchar(); 17 } 18 while( isdigit(c) ){ 19 s = s * 10 + c - '0'; c = getchar(); 20 } 21 return s * t; 22 } 23 24 int try_to_insert(int s) 25 { 26 int h = num[s] % mod; if( h < 0 ) h = -h; 27 int u = head[h]; 28 while( u ){ 29 if( num[u] == num[s] ) return 0; 30 u = next[u]; 31 } 32 next[s] = head[h]; 33 head[h] = s; 34 return 1; 35 } 36 37 int main() 38 { 39 int t = read(); 40 while( t-- ){ 41 memset(head,0,sizeof(head)); 42 int n = read(); 43 bool first = 1; 44 rep(i,1,n){ 45 num[i] = read(); 46 if( try_to_insert(i) ){ 47 if( first ) { 48 printf("%d", num[i]); 49 first = 0; 50 } 51 else printf(" %d", num[i]); 52 } 53 } 54 printf("\n"); 55 } 56 return 0; 57 }
2761: [JLOI2011]不重复数字
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3089 Solved: 1143
[Submit][Status][Discuss]
Description
给出N个数,要求把其中重复的去掉,只保留第一次出现的数。
例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4。
Input
输入第一行为正整数T,表示有T组数据。
接下来每组数据包括两行,第一行为正整数N,表示有N个数。第二行为要去重的N个正整数。
Output
对于每组数据,输出一行,为去重后剩下的数字,数字之间用一个空格隔开。
Sample Input
2
11
1 2 18 3 3 19 2 3 6 5 4
6
1 2 3 4 5 6
11
1 2 18 3 3 19 2 3 6 5 4
6
1 2 3 4 5 6
Sample Output
1 2 18 3 19 6 5 4
1 2 3 4 5 6
1 2 3 4 5 6
HINT
对于30%的数据,1 <= N <= 100,给出的数不大于100,均为非负整数;
对于50%的数据,1 <= N <= 10000,给出的数不大于10000,均为非负整数;
对于100%的数据,1 <= N <= 50000,给出的数在32位有符号整数范围内。
提示:
由于数据量很大,使用C++的同学请使用scanf和printf来进行输入输出操作,以免浪费不必要的时间。
————————————————