【字串】字串雜湊
阿新 • • 發佈:2021-08-10
目錄
字串雜湊
雜湊
雜湊就是將所要處理的資料轉化成數字,且這個數字能唯一地去對應上這個資料,若這個數字對應上了多個數字,則稱作雜湊衝突。比如\(K_{1}!=K_{2}\),但\(hash(K_{1})=hash({K_{2}})\)
字串雜湊
概念:字串雜湊是指將一個任意長度的字串對映成一個非負整數,並且衝突的概率幾乎為0.
字串的雜湊衝突:
衝突:兩個字串不相等,但是他們的p進位制數相同
字串雜湊的思想
將字串看成一連串的數字,字串裡的每一位看成在某一個特定位置上的單獨的數字,並對這個數字賦予一定的權值,設為P(也用P來指說字串可以看成是一個P進位制數),這時候我們可以將由代表這個字串的P進位制數轉化成十進位制數, 並向一個固定的數M取餘(M代表的是雜湊值的範圍).
- P一般取131或者13331,如果題目的字串僅有小寫字母,可以考慮取26.
- M可以設定成是2的64次方(只需unsigned long long),一方面,超出上界(溢位)後,數值會自動從0開始計算,這種天然的取餘操作相比於再去使用mod取餘操作會更高效.(面向一些大質數取餘,比如1E9,能減少雜湊衝突的概率(數論的知識,還不太懂)),另一方面,unsigned long long 具有資料範圍大,能容納的雜湊值更多.
例子: 我們將a~z一一與1到26對應
\(hash("abcb")=a*P^{3}+b*P^{2}+c*P^{1}+b*P^{0}\)
字串雜湊的基本運算
- 已知某一字串的雜湊值,在其字串的尾巴繼續添置一個字母,求新組成的字串的雜湊值.
\(hash("abcb"+'d') =hash("abcbd")=(a*P^{4}+b*P^{3}+c*P^{2}+b*P^{1}+d=hash("abcb")*P+d)\%\space mod\)
-
進而我們有,已知字串S和字串T的雜湊值,求S+T的雜湊值
\[H(S+T)=(H(S)\times P^{len-of-T}+H(T))\% \space mod$$ \]\[H(T) =(H(S+T)-H(S)*P^{len-of-T})\%\space mod$$ \]
AcWing 138. 兔子與兔子
#include <bits/stdc++.h> #define MEM(a,x) memset(a,x,sizeof(a)) #define W(a) while(a) #define gcd(a,b) __gcd(a,b) #define pi acos(-1.0) #define PII pair<int,int> #define pb push_back #define mp make_pair #define fi first #define se second #define ll long long #define ull unsigned long long #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define MAX 1000005 #define MOD 1000000007 #define INF 0x3f3f3f3f #define lowbit(x) (x&-x) using namespace std; int n,m; const int P=131,N = 1E6+10; ull h[N],mul[N]; void pre_work(string s) { MEM(h,0); mul[0]=1; repd(i,1,s.length()) { h[i]=h[i-1]*P+(s[i-1]-'a'+1); mul[i]=mul[i-1]*P; } } int main() { string dna; int t; cin>>dna>>t; pre_work(dna); while(t--) { int l1,r1,l2,r2; cin>>l1>>r1>>l2>>r2; if( (h[r1]-h[l1-1]*mul[r1-l1+1]) == (h[r2]-h[l2-1]*mul[r2-l2+1]) ) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }