哈希
——————————18.5.14更新
——————————18.5.15更新 哈希的判斷
哈希是神馬東西呢。。。。簡單來說它是一個函數啦。。。就這麼樣(好難呀)
哈希的簡介
它是將一個複雜的字符串用一個函數將它映射成一個數字的過程。哈希的函數有很多,也很玄學,因爲它看起來很容易錯,有很多反例,但是它就是不錯。它主要用於判斷兩個字符串是否相等,具體地實現是判斷兩個字符的哈希函數的值是否一樣即可。
哈希的函數
一下函數都是針對一個字符串A的:(其中 是質數, 爲字符串長度, 爲該位字符在該字符串中出現次數)
還有一個特殊的一個函數:
兩個字符串的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. 計算A中A[l]至A[r]的hash值
想一想我們之前算出的hash值儲存方式中每個數組的值是什麼?:
可推得:
而p的次冪可以數組預處理儲存,就 計算了。在線計算是 的
當然,也可以推得前面另一種hash函數的A[l]-A[r]的值,不過要求出逆元,要複雜一些(
2.雙哈希
有些題的數據很強,哈希很容易被卡(哈希很玄學),所以要用到它。顧名思義,即蛤兩次,比較兩個hash值的大小即可。注意兩個hash函數的mod必須不一樣。