哈希(蛤鉿)

哈希

——————————18.5.14更新

——————————18.5.15更新 哈希的判斷

哈希是神馬東西呢。。。。簡單來說它是一個函數啦。。。就這麼樣(好難呀)

哈希的簡介

它是將一個複雜的字符串用一個函數將它映射成一個數字的過程。哈希的函數有很多,也很玄學,因爲它看起來很容易錯,有很多反例,但是它就是不錯。它主要用於判斷兩個字符串是否相等,具體地實現是判斷兩個字符的哈希函數的值是否一樣即可。

哈希的函數

一下函數都是針對一個字符串A的:(其中p 是質數,len 爲字符串長度,cntAi 爲該位字符在該字符串中出現次數)

hash(A)=i=1lenAipi

hash(A)=i=1lenAipleni

還有一個特殊的一個函數:
hash(A)=i=1lenAipcntAi

兩個字符串的hash值相同,我們就可以認爲兩個字符串相等。

具體實現哈希的方法

1.取模

首先我們要取兩個很棒的質數p,mod,p表示哈希函數中的p,mod是hash函數的取模(因爲哈希函數的值十分大,取模才能比較大小,而且mod比p的選取更加重要)
這裏介紹幾個很棒的質數:(mod=1234321237,998244353)(p=1e9+7,1e9+9)
代碼:

long long hash[maxn],p,mod;//longlong避免溢出 
void gethash(string a){
    int i,len=a.length();
    hsh[0]=a[0];
    for(i=1;i<len;i++)
        hsh[i]=((hsh[i-1]*p)%mod+a[i])%mod;//計算從首位到該位構成的子串的hash值 
}

2.自然溢出(稍微比取模好)

運用longlong有上限的功能,將hash值模longlong的上限,常數更小。(要用到unsigned long long,因爲它取不到負數)
代碼:

unsigned long long hash[maxn],p;//unsigned long long 取不到負數 
void gethash(string a){
    int i,len=a.length();
    hsh[0]=a[0];
    for(i=1;i<len;i++)
        hsh[i]=hsh[i-1]*pa[i];//計算從首位到該位構成的子串的hash值 
}

哈希的技巧

1.O1 計算A中A[l]至A[r]的hash值

想一想我們之前算出的hash值儲存方式中每個數組的值是什麼?:

hash(k)=i=1kaipleni

hash(l,r)=i=lraipri=i=1raiprii=1laipliprl

可推得:
hash(l,r)=hashrhash(l1)prl

而p的次冪可以數組預處理儲存,就O1 計算了。在線計算是Ologn
當然,也可以推得前面另一種hash函數的A[l]-A[r]的值,不過要求出逆元,要複雜一些(玄學出錯)。

2.雙哈希

有些題的數據很強,哈希很容易被卡(哈希很玄學),所以要用到它。顧名思義,即蛤兩次,比較兩個hash值的大小即可。注意兩個hash函數的mod必須不一樣。

這些就是hash的內容了,以後應該會更哈希樹的內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章