使用unsigned long long来做自然溢出
#include <iostream>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e5 + 10, P = 131;
ULL h[N], p[N];
char s[N];
int n, m;
ULL sub_hash(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
int main() {
scanf("%d%d\n%s\n", &n, &m, s + 1);
p[0] = 1L;
for (int i = 1; i <= n; ++i) {
h[i] = h[i - 1] * P + s[i];
p[i] = p[i - 1] * P;
}
while (m--) {
int l1, r1, l2, r2;
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
puts(sub_hash(l1, r1) == sub_hash(l2, r2) ? "Yes" : "No");
}
return 0;
}
作者:GabrielxD
链接:https://www.acwing.com/solution/content/148484/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
不做自然溢出,单值hash
// 字符串哈希模板开始
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int rnd(int x, int y) {
return uniform_int_distribution<int>(x, y)(rng);
}
int MOD = 998244353 + rnd(0, 1e9), BASE = 233 + rnd(0, 1e3);
struct HashSeq {
vector<long long> P, H;
HashSeq() {}
HashSeq(string &s) {
int n = s.size();
P.resize(n + 1);
P[0] = 1;
for (int i = 1; i <= n; i++) P[i] = P[i - 1] * BASE % MOD;
H.resize(n + 1);
H[0] = 0;
for (int i = 1; i <= n; i++) H[i] = (H[i - 1] * BASE + (s[i - 1] ^ 7)) % MOD;
}
long long query(int l, int r) {
return (H[r] - H[l - 1] * P[r - l + 1] % MOD + MOD) % MOD;
}
};
// 字符串哈希模板结束
class Solution {
public:
long long countPrefixSuffixPairs(vector<string>& words) {
int n = words.size();
vector<HashSeq> hs;
for (auto &s : words) hs.push_back(HashSeq(s));
int mx = 0;
for (auto &s : words) mx = max(mx, (int) s.size());
// cnt[l][h] 表示目前有几个长度为 l,且哈希值为 h 的字符串
unordered_map<long long, int> cnt[mx + 1];
long long ans = 0;
// 枚举每个字符串
for (int i = 0; i < n; i++) {
int len = words[i].size();
// 枚举每个前缀
for (int j = 1; j <= len; j++) {
long long h1 = hs[i].query(1, j), h2 = hs[i].query(len - j + 1, len);
// 首先检查这个前缀是否也是后缀,如果是,则答案增加
if (h1 == h2 && cnt[j].count(h1)) ans += cnt[j][h1];
}
// 把当前字符串加入哈希表
cnt[len][hs[i].query(1, len)]++;
}
return ans;
}
};
作者:TsReaper
链接:https://leetcode.cn/circle/discuss/ZnbNSt/view/nXnhq5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
双值hash
namespace utils {
static int D = 127;
static int mod1 = 1e9 + 7, mod2 = 1e9 + 9;
vector<long long> pow1, pow2;
void init(int l) {
pow1.resize(l + 1, 0);
pow1[0] = 1; pow2 = pow1;
for (int i = 1; i <= l; i ++)
pow1[i] = pow1[i - 1] * D % mod1,
pow2[i] = pow2[i - 1] * D % mod2;
}
int qmod(int v, int m) {
return v + ((v >> 31) & m);
}
struct Hash {
vector<long long> val1, val2;
Hash(string s) {
val1.reserve(s.size());
val2.reserve(s.size());
long long v1 = 0, v2 = 0;
for (auto c: s) {
v1 = (v1 * D + c) % mod1;
v2 = (v2 * D + c) % mod2;
val1.push_back(v1);
val2.push_back(v2);
}
}
pair<int, int> val() {
return {val1.back(), val2.back()};
}
pair<int, int> val(int l, int r) {
if (l == 0)
return {val1[r], val2[r]};
return {
qmod(val1[r] - val1[l - 1] * pow1[r - l + 1] % mod1, mod1),
qmod(val2[r] - val2[l - 1] * pow2[r - l + 1] % mod2, mod2)
};
}
};
}
using utils::Hash;
using utils::init;
pair<int, int> H(string s) {
return Hash(s).val();
}
class Solution {
public:
long long countPrefixSuffixPairs(vector<string>& words) {
init(1e5);
map<pair<int, int>, int> mp;
long long ans = 0;
for (int i = 0; i < (int)words.size(); i ++) {
auto h = Hash(words[i]);
for (int l = 1; l <= (int)words[i].size(); l ++) {
if (h.val(0, l - 1) == h.val(words[i].size() - l, words[i].size() - 1))
ans += mp[h.val(0, l - 1)];
}
++ mp[h.val()];
}
return ans;
}
};