時/空限制:1s / 64mb
給定乙個長度為n的字串,再給定m個詢問,每個詢問包含四個整數l1,r1,l2,r2,請你判斷[l1,r1]和[l2,r2]這兩個區間所包含的字串子串是否完全相同。
字串中只包含大小寫英文本母和數字。
第一行包含整數n和m,表示字串長度和詢問次數。
第二行包含乙個長度為n的字串,字串中只包含大小寫英文本母和數字。
接下來m行,每行包含四個整數l1,r1,l2,r2,表示一次詢問所涉及的兩個區間。
注意,字串的位置從1開始編號。
對於每個詢問輸出乙個結果,如果兩個字串子串完全相同則輸出「yes」,否則輸出「no」。
每個結果佔一行。
1≤n,m≤10^5
8 3aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2
yes題意:判斷[l1,r1]和[l2,r2]這兩個區間所包含的字串子串是否完全相同。noyes
思路:將字串看成p進製數(判斷兩個整數是否相等好判斷),p的經驗值是131或13331,取這兩個值的衝突概率低。
根據定義分別求出hash[i]:
現在我們想求s3s4的hash值,不難得出為s3∗p+s4,並且從上面觀察,如果看hash[4]−hash[2]並將結果中帶有s1,s2係數的項全部消掉,就是所求。但是由於p的階數,不能直接消掉,所以問題就轉化成,將hash[2]乘乙個關於p的係數,在做差的時候將多餘項消除,從而得到結果。
不難發現,對應項係數只差乙個p^2,而4-3+1=2(待求hash子串下標相減再加一),這樣就不難推導出來此例題的求解式子。hash[4]−hash[2]∗p^(4−2+1)
至此,通過對上例的歸納,可以得出如下的公式:
若已知乙個|s|=n的字串的hash值,hash[i],1≤i≤n,其子串sl..sr,1≤l≤r≤n對應的hash值為:
考慮到hash[i]每次對p取模,進一步得到下面的式子:hash=(hash[r]−hash[l−1]∗p^(r−l+1))%mod。
注意到括號裡面有可能是負數,故:hash=((hash[r]−hash[l−1]∗p^(r−l+1))%mod+mod)%mod。
至此得到求子串hash值公式。取模的數用2^64,這樣直接用unsigned long long儲存,溢位的結果就是取模的結果。
accepted code:
/*
* @author: lzyws739307453
* @language: c++
*/#include using namespace std;
const int p = 131;
const int maxn = 1e5 + 5;
typedef unsigned long long ull;
ull h[maxn], p[maxn]; // h[k]儲存字串前k個字母的雜湊值, p[k]儲存 p^k mod 2^64
char str[maxn];
// 初始化
void init(int n)
}// 計算子串 str[l ~ r] 的雜湊值
ull get(int l, int r)
int main()
return 0;
}
Hash 字串 字串雜湊
luo gu luogu luogup 3370 p3370 p337 0如題,給定n個字串 第i個字串長度為mi,字串內包含數字 大小寫字母 請求出n個字串中共有多少個不同的字串。第一行包含乙個整數n,為字串的個數。接下來n行每行包含乙個字串,為所提供的字串。輸出包含一行,包含乙個整數,為不同的字...
字串演算法 字串雜湊
方法以,m進製的形式來表示乙個字串,那麼這個字串就可以輕鬆計算 i j 之間的hash值 當只有小寫 大家字母時,m 131 而hash值,可以使用unsigned long long 來表示,這時不再需要求餘 方法應用 字串匹配。思路 對比hash值 允許k次失配的字串匹配 即 允許k次字元值不對...
字串雜湊
參照演算法筆記p109,甲級1039 先假設字串均由大寫字母a z構成。在這個基礎上,不妨把a z視為0 25,這樣就把26個大寫字母對應到了26進製中。接著,按照將26進製轉化為10進製的思路,由進製的轉換結論可知,在進製轉換過程中,得到的10進製肯定是唯一的,由此便可實現將字串對映為整數的需求 ...