就是构造两个哈希函数,然后将结果记为pair存map,能够进一步减少冲突率
例题:Birthday Cake
题意
给你n个串,问有几对串可以拼成形如AA串。
思路
先对所有串跑一个哈希,然后遍历所有串,如果该串是ABA型那么就去找B的个数,自然溢出法还差一点,双哈希就过了。
ac代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define pll pair<ll,ll>
const int maxn = 4e5 + 5;
ll Mod1 = 1e9 + 9, Mod2 = 1e9 + 11;
ll ha1[maxn], ha2[maxn], p1[maxn], p2[maxn], bas = 233;
pll res[maxn];
int cc = 0;
map<pll, ll> cnt;
ll get1(int l, int r){ //子串hash1
return (ha1[r] - ha1[l - 1] * p1[r - l + 1] % Mod1 + Mod1 ) % Mod1;
}
ll get2(int l, int r){ //子串hash2
return (ha2[r] - ha2[l - 1] * p2[r - l + 1] % Mod2 + Mod2 ) % Mod2;
}
pll get(int l, int r){ //成pair用于存map,或者计算数量
return {get1(l, r), get2(l, r)};
}
int main(){
cin.tie(0);ios::sync_with_stdio(false);
int n; cin >> n;
//预处理bas的幂次,用于获取子串用
p1[0] = 1;
for(int i = 1; i < maxn; i ++) p1[i] = p1[i - 1] * bas % Mod1;
p2[0] = 1;
for(int i = 1; i < maxn; i ++) p2[i] = p2[i - 1] * bas % Mod2;
for(int i = 1; i <= n; i ++){
string a; cin >> a;
int len = a.length();
for(int j = 1; j <= len; j ++){
//跑hash数组
ha1[j] = ha1[j - 1] * bas % Mod1 + a[j - 1] - 'a' + 1;
ha2[j] = ha2[j - 1] * bas % Mod2 + a[j - 1] - 'a' + 1;
ha1[j] %= Mod1; ha2[j] %= Mod2;
}
cnt[{ha1[len], ha2[len]}] ++;
for(int j = 1; j + j < len; j ++){
if(get(1, j) == get(len - j + 1, len)) res[++ cc] = get(j + 1, len - j); // 如果是ABA型就先把B存下来,最后一起找
}
}
ll ans = 0;
for(int i = 1; i <= cc; i ++) ans += cnt[res[i]];
for(auto it : cnt) ans += it.second * (it.second - 1) / 2; //这里是同一个串出现超过1次的情况
cout << ans << endl;
return 0;
}