idea建立一個乾淨的SpringMVC專案
阿新 • • 發佈:2021-11-27
字串雜湊
雜湊基本思想就是兩個物件的對映,字串雜湊則是將一個字串對映到一個數上,用這個數即可代表這個字串,而這個數被稱為雜湊值
那麼如何計算雜湊值呢?
我們知道字串的每個字元其實相等於一個數字,因此我們可以把每個字串看成一個整數,之後將其轉化為P進位制下mod一個質數的數字,而這個數也就是這個字串的雜湊值。
例:"ABCD" -----> \((A\times P^3+B\times P^2+C\times P^1+D\times P^0) \,mod \,K\)
一般我們取P為131 或 13331, Q 為 \(2^{64}\)可以保證大部分情況下不出現雜湊衝突
而mod Q 的操作我們可以通過將變數定義為unsigned long long來省略,因為在ull下當數值溢位範圍後會自動對\(2^{64}\) 取模
雜湊字首
我們定義h[i] 表示字串第1個到第i個字元組成的子串的雜湊值
那如何求l到r的子串雜湊值呢?
結論:res = h[r] - h[l - 1] * p[r - l + 1]
**我們不能直接向前綴和那樣h[r] - h[l - 1], 因為此時在h[r]中1 - l-1的雜湊值與h[l - 1]並不相同,而差的值正好就是他們直接相差的位數,因此乘上\(p^{r-l+1}\)即可,這裡我們已經預處理p[i]來表示\(p^i\)了 **
通過這樣的方法在預處理後我們可以用\(O(1)\)的複雜度獲得一段字元的雜湊值,並利用雜湊值高效完成一系列其他操作
程式碼示例:
//#pragma comment(linker, "/STACK:10240000000000,10240000000000") //#pragma GCC optimize(2) #include <bits/stdc++.h> using namespace std; #define rep(i,a,b) for (int i=(a);i<=(b);++i) #define per(i,b,a) for (int i=(b);i>=(a);--i) #define lb lower_bound #define ub upper_bound #define pb push_back #define itt iterator #define endl '\n' #define IOS ios::sync_with_stdio(0); cin.tie(0); #define lowbit(x) x & (-x) #define clr(x) memset(x, 0, sizeof(x)); #define fi first #define se second #define mp make_pair #define MOD 1000000007 typedef vector<int> vii; typedef vector<long long> vll; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef set<int> si; typedef set<ll> sll; ll ksm(ll a, ll b, ll p) {if (b == 0) return 1; ll ns = ksm(a, b >> 1, p); ns = ns * ns % p; if (b & 1) ns = ns * a % p; return ns;} const int MAXN = 0x7fffffff; const int N = 1e5 + 5, P = 131; ull p[N]; ull h[N]; int n, m; char str[N]; ull get(int l, int r) { return h[r] - h[l - 1] * p[r - l + 1]; } int main () { //IOS; cin >> n >> m; cin >> str + 1; p[0] = 1; for(int i = 1; i <= n; i ++) { p[i] = p[i - 1] * P; //預處理p陣列 h[i] = h[i - 1] * P + str[i];//預處理雜湊字首陣列 } while(m --) { int l1, r1, l2, r2; cin >> l1 >> r1 >> l2 >> r2; if(get(l1, r1) == get(l2, r2)) puts("Yes"); else puts("No"); } return 0; } /* */