整数判重、大整数Hash
大整數(shù)Hash
總是聽高屆的大佬說,一個(gè)字符串Hash,能搞出大部分的字符串題,Hash真的有那么神嗎?
答:是的
近來,參加很多NOIP模擬賽,其中一場(chǎng)設(shè)計(jì)判斷大整數(shù)是否存在偷懶了一下,開了一個(gè)map原本能A的題T掉了三個(gè)點(diǎn),OJ上評(píng)測(cè)T3個(gè)點(diǎn)還跑了1480ms,忍痛改Hash后發(fā)現(xiàn)A了只跑了356ms
對(duì)于整數(shù)的判重、Hash事實(shí)上有很多方法,具體應(yīng)用要看數(shù)據(jù)范圍和題目要求
看大整數(shù)HASH好多博客都是工業(yè)編程,那我就寫個(gè)OI的吧,接下來就列舉一些常見判重方法
1.數(shù)組判重
數(shù)組判重是一種較為常見的方式,我以前很常用,桶排序(多種叫法)就是類似于這樣的
優(yōu)點(diǎn):速度快,單次O(1),支持統(tǒng)計(jì)次數(shù),可以動(dòng)態(tài)
缺點(diǎn):支持范圍小,數(shù)組可能會(huì)開不下,數(shù)據(jù)在10^8及以上基本就不能使用了
2.set、map判重
set、map判重簡(jiǎn)單又方便,還有各種高級(jí)功能,但由于調(diào)用STL,速度會(huì)有點(diǎn)慢
優(yōu)點(diǎn):功能多,使用方便,一般數(shù)據(jù)不大可以使用,map支持統(tǒng)計(jì)次數(shù),可以動(dòng)態(tài),支持的范圍較大,只要數(shù)字?jǐn)?shù)量不爆就能開下
缺點(diǎn):速度較慢,常數(shù)可能會(huì)優(yōu)點(diǎn)大,單次O(logn)
3.二分判重
二分判重,比較傳統(tǒng),手打的常數(shù)小,相較于map性能更好,但是功能不多
優(yōu)點(diǎn):常數(shù)小,支持范圍也較大(同set、map),較為簡(jiǎn)單
缺點(diǎn):單次還是O(logn),功能少,不支持動(dòng)態(tài),而且統(tǒng)計(jì)次數(shù)會(huì)增加常數(shù)
4.平衡樹
各種平衡樹都還行,但是我比較菜,手打容易打掛,但是整體性能不得不承認(rèn)還是可以的
優(yōu)點(diǎn):常數(shù)小,支持范圍也較大(同set、map),功能也比較多,支持動(dòng)態(tài)還能統(tǒng)計(jì)次數(shù)
缺點(diǎn):單次還是O(logn),打起來麻煩
5.整數(shù)HASH
Hash真的有用,信仰的力量!!!
優(yōu)點(diǎn):常數(shù)小,支持范圍較大,支持動(dòng)態(tài)、可以統(tǒng)計(jì)次數(shù),單次O(1)!!!打起來也不煩
缺點(diǎn):打Hash要看臉,可以故意來卡你(但隨機(jī)數(shù)一般卡不了)
具體代碼+注釋介紹
#include<cstdio> #include<cstring> inline int max(const int a,const int b){return a>b?a:b;}//手寫,讓這些函數(shù)的常數(shù)小一點(diǎn) inline int min(const int a,const int b){return a<b?a:b;} inline int abs(const int a){return a>0?a:-a;} inline void swap(int&a,int&b){int c=a;a=b;b=c;} inline void read(int&x)//可讀負(fù)數(shù)的讀入優(yōu)化 {char cu=getchar();x=0;bool fla=0;while(cu<'0'||cu>'9'){if(cu=='-')fla=1;cu=getchar();}while('0'<=cu&&cu<='9')x=x*10+cu-'0',cu=getchar();if(fla)x=-x; } void printe(const int x) {if(x>=10)printe(x/10);putchar(x%10+'0'); } inline void print(const int x)//可輸負(fù)數(shù)的輸出優(yōu)化 {if(x<0)putchar('-'),printe(-x);else printe(x); } namespace bigHash//打板子,當(dāng)然放一個(gè)namespace方便使用 {const int mod=100007,maxn=100001;//mod可以自己調(diào),maxn是不同元素的種類數(shù)量int head[mod],nxt[maxn],vau[maxn],tmp=0;int tow[maxn];inline void add(const int x)//加入元素{int whom=x%mod;for(int i=head[whom];~i;i=nxt[i])if(tow[i]==x){vau[i]++;return;}tmp++;nxt[tmp]=head[whom];head[whom]=tmp;tow[tmp]=x;vau[tmp]++;}inline bool find(const int x)//查找元素是否存在1存在0不存在{int whom=x%mod;for(int i=head[whom];~i;i=nxt[i])if(tow[i]==x)return 1;return 0;}inline int get(const int x)//獲得數(shù)字x的數(shù)量{int whom=x%mod;for(int i=head[whom];~i;i=nxt[i])if(tow[i]==x)return vau[i];return 0;}inline void init()//初始化{memset(head,-1,sizeof(head)); } } using namespace bigHash; int main() {init();//初始化int n,q;read(n);//開始的數(shù)組的數(shù)字個(gè)數(shù)for(int i=1;i<=n;i++){int a;read(a);add(a);}read(q);//詢問for(int i=1;i<=q;i++){int a;read(a);if(find(a))print(get(a));//如果存在輸出數(shù)量else print(0);//否則輸出0putchar('\n');}return 0; }這個(gè)Hash的原理其實(shí)很簡(jiǎn)單,如圖,具體會(huì)不會(huì)被卡要看你的模數(shù)咋樣,一般取一個(gè)質(zhì)數(shù)比較保險(xiǎn)
嗯,就講到這吧,如發(fā)現(xiàn)有問題可以提出,有問題也可以問我哦
總結(jié)
以上是生活随笔為你收集整理的整数判重、大整数Hash的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017/9/26Codeforces
- 下一篇: 最长上升子序列(LIS)的求法