https://www.acwing.com/problem/content/158/
题意:给一个01矩阵,把它哈希之后,给若干个大小固定的01矩阵,问在不在其中。
讲道理实际上用ull,比1e18还多一点(虽然未必可以取完),首次哈希冲突的期望次数在sqrt(空间),所以就是不可能!
三个ull哈希,被卡内存而削减到只剩一个。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
unordered_set<ull >MAP;
int n, m, a, b;
int g[1005][1005];
ull ha1[1005][1005];
//ull ha2[1005][1005];
//ull ha3[1005][1005];
const ull BASE1 = 23333ll;
//const ull BASE2 = 2333333ll;
//const ull BASE3 = 19260817ll;
const ull BASE12 = 2333388ll;
//const ull BASE22 = 233333388ll;
//const ull BASE32 = 1926081788ll;
ull qpow(ull x, int n) {
ull res = 1;
while(n) {
if(n & 1)
res = res * x;
x = x * x;
n >>= 1;
}
return res;
}
void init1(int i) {
ull p1 = qpow(BASE1, b);
// ull p2 = qpow(BASE2, b);
// ull p3 = qpow(BASE3, b);
ull cur1 = 0;
// ull cur2 = 0;
// ull cur3 = 0;
for(int j = 0; j < b; ++j) {
cur1 = cur1 * BASE1 + g[i][j];
// cur2 = cur2 * BASE2 + g[i][j];
// cur3 = cur3 * BASE3 + g[i][j];
}
ha1[i][0] = cur1;
// ha2[i][0] = cur2;
// ha3[i][0] = cur3;
for(int j = b; j < m; ++j) {
cur1 = cur1 * BASE1 + g[i][j];
cur1 = cur1 - g[i][j - b] * p1;
// cur2 = cur2 * BASE2 + g[i][j];
// cur2 = cur2 - g[i][j - b] * p2;
// cur3 = cur3 * BASE3 + g[i][j];
// cur3 = cur3 - g[i][j - b] * p3;
ha1[i][j - b + 1] = cur1;
// ha2[i][j - b + 1] = cur2;
// ha3[i][j - b + 1] = cur3;
/*printf("i=%d j=%d ha1=%llu
", i, j, ha1[i][j - b + 1]);
printf("i=%d j=%d ha2=%llu
", i, j, ha2[i][j - b + 1]);
printf("i=%d j=%d ha3=%llu
", i, j, ha2[i][j - b + 1]);
printf("
");*/
}
//printf("
");
}
ull haha1[1005][1005];
//ull haha2[1005][1005];
//ull haha3[1005][1005];
void init2(int j) {
ull p1 = qpow(BASE12, a);
// ull p2 = qpow(BASE22, a);
// ull p3 = qpow(BASE32, a);
ull cur1 = 0;
// ull cur2 = 0;
// ull cur3 = 0;
for(int i = 0; i < a; ++i) {
cur1 = cur1 * BASE12 + ha1[i][j];
// cur2 = cur2 * BASE22 + ha2[i][j];
// cur3 = cur3 * BASE32 + ha3[i][j];
}
haha1[0][j] = cur1;
// haha2[0][j] = cur2;
// haha3[0][j] = cur3;
for(int i = a; i < n; ++i) {
cur1 = cur1 * BASE12 + ha1[i][j];
cur1 = cur1 - ha1[i - a][j] * p1;
// cur2 = cur2 * BASE22 + ha2[i][j];
// cur2 = cur2 - ha2[i - a][j] * p2;
// cur3 = cur3 * BASE32 + ha3[i][j];
// cur3 = cur3 - ha3[i - a][j] * p3;
haha1[i - a + 1][j] = cur1;
// haha2[i - a + 1][j] = cur2;
// haha3[i - a + 1][j] = cur3;
/*printf("i=%d j=%d haha1=%llu
", i, j, haha1[i][j]);
printf("i=%d j=%d haha2=%llu
", i, j, haha2[i][j]);
printf("i=%d j=%d haha3=%llu
", i, j, haha3[i][j]);
printf("
");*/
}
//printf("
");
}
void insert(int si, int sj) {
ull cur1 = haha1[si][sj];
// ull cur2 = haha2[si][sj];
// ull cur3 = haha3[si][sj];
// MAP[cur1].push_back({cur2, cur3});
MAP.insert(cur1);
}
bool find() {
ull cur1 = 0;
// ull cur2 = 0;
// ull cur3 = 0;
int cur;
for(int i = 0; i < a; ++i) {
ull tcur1 = 0;
// ull tcur2 = 0;
// ull tcur3 = 0;
for(int j = 0; j < b; ++j) {
scanf("%1d", &cur);
//printf("%d", cur);
tcur1 = tcur1 * BASE1 + cur;
// tcur2 = tcur2 * BASE2 + cur;
// tcur3 = tcur3 * BASE3 + cur;
}
cur1 = cur1 * BASE12 + tcur1;
// cur2 = cur2 * BASE22 + tcur2;
// cur3 = cur3 * BASE32 + tcur3;
//printf("
");
}
/*printf("cur1=%llu
", cur1);
printf("cur2=%llu
", cur2);
printf("cur3=%llu
", cur3);*/
if(MAP.count(cur1)) {
// vector < pair<ull, ull> > vec = MAP[cur1];
// for(auto i : vec) {
// if(i.first == cur2 && i.second == cur3)
// return 1;
// }
return 1;
}
return 0;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
scanf("%d%d%d%d", &n, &m, &a, &b);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j)
scanf("%1d", &g[i][j]);
}
for(int i = 0; i < n; ++i)
init1(i);
for(int j = 0; j + b <= m; ++j)
init2(j);
for(int i = 0; i + a <= n; ++i) {
for(int j = 0; j + b <= m; ++j) {
insert(i, j);
/*printf("i=%d j=%d haha1=%llu
", i, j, haha1[i][j]);
printf("i=%d j=%d haha2=%llu
", i, j, haha2[i][j]);
printf("i=%d j=%d haha3=%llu
", i, j, haha3[i][j]);
printf("
");*/
}
//printf("
");
}
int t;
scanf("%d", &t);
while(t--) {
printf("%d
", find());
}
}
正常的三哈希?原本的模数因为溢出被卡了,重新选了一群质数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned short ull;
unordered_map<ull, vector<pair<ull, ull> > >MAP;
int n, m, a, b;
int g[1005][1005];
ull ha1[1005][1005];
ull ha2[1005][1005];
ull ha3[1005][1005];
const ull BASE1 = 233ll;
const ull BASE2 = 131ll;
const ull BASE3 = 37ll;
const ull BASE12 = 13ll;
const ull BASE22 = 97ll;
const ull BASE32 = 47ll;
ull qpow(ull x, int n) {
ull res = 1;
while(n) {
if(n & 1)
res = res * x;
x = x * x;
n >>= 1;
}
return res;
}
void init1(int i) {
ull p1 = qpow(BASE1, b);
ull p2 = qpow(BASE2, b);
ull p3 = qpow(BASE3, b);
ull cur1 = 0;
ull cur2 = 0;
ull cur3 = 0;
for(int j = 0; j < b; ++j) {
cur1 = cur1 * BASE1 + g[i][j];
cur2 = cur2 * BASE2 + g[i][j];
cur3 = cur3 * BASE3 + g[i][j];
}
ha1[i][0] = cur1;
ha2[i][0] = cur2;
ha3[i][0] = cur3;
for(int j = b; j < m; ++j) {
cur1 = cur1 * BASE1 + g[i][j];
cur1 = cur1 - g[i][j - b] * p1;
cur2 = cur2 * BASE2 + g[i][j];
cur2 = cur2 - g[i][j - b] * p2;
cur3 = cur3 * BASE3 + g[i][j];
cur3 = cur3 - g[i][j - b] * p3;
ha1[i][j - b + 1] = cur1;
ha2[i][j - b + 1] = cur2;
ha3[i][j - b + 1] = cur3;
/*printf("i=%d j=%d ha1=%llu
", i, j, ha1[i][j - b + 1]);
printf("i=%d j=%d ha2=%llu
", i, j, ha2[i][j - b + 1]);
printf("i=%d j=%d ha3=%llu
", i, j, ha2[i][j - b + 1]);
printf("
");*/
}
//printf("
");
}
ull haha1[1005][1005];
ull haha2[1005][1005];
ull haha3[1005][1005];
void init2(int j) {
ull p1 = qpow(BASE12, a);
ull p2 = qpow(BASE22, a);
ull p3 = qpow(BASE32, a);
ull cur1 = 0;
ull cur2 = 0;
ull cur3 = 0;
for(int i = 0; i < a; ++i) {
cur1 = cur1 * BASE12 + ha1[i][j];
cur2 = cur2 * BASE22 + ha2[i][j];
cur3 = cur3 * BASE32 + ha3[i][j];
}
haha1[0][j] = cur1;
haha2[0][j] = cur2;
haha3[0][j] = cur3;
for(int i = a; i < n; ++i) {
cur1 = cur1 * BASE12 + ha1[i][j];
cur1 = cur1 - ha1[i - a][j] * p1;
cur2 = cur2 * BASE22 + ha2[i][j];
cur2 = cur2 - ha2[i - a][j] * p2;
cur3 = cur3 * BASE32 + ha3[i][j];
cur3 = cur3 - ha3[i - a][j] * p3;
haha1[i - a + 1][j] = cur1;
haha2[i - a + 1][j] = cur2;
haha3[i - a + 1][j] = cur3;
/*printf("i=%d j=%d haha1=%llu
", i, j, haha1[i][j]);
printf("i=%d j=%d haha2=%llu
", i, j, haha2[i][j]);
printf("i=%d j=%d haha3=%llu
", i, j, haha3[i][j]);
printf("
");*/
}
//printf("
");
}
void insert(int si, int sj) {
ull cur1 = haha1[si][sj];
ull cur2 = haha2[si][sj];
ull cur3 = haha3[si][sj];
MAP[cur1].push_back({cur2, cur3});
}
bool find() {
ull cur1 = 0;
ull cur2 = 0;
ull cur3 = 0;
int cur;
for(int i = 0; i < a; ++i) {
ull tcur1 = 0;
ull tcur2 = 0;
ull tcur3 = 0;
for(int j = 0; j < b; ++j) {
scanf("%1d", &cur);
//printf("%d", cur);
tcur1 = tcur1 * BASE1 + cur;
tcur2 = tcur2 * BASE2 + cur;
tcur3 = tcur3 * BASE3 + cur;
}
cur1 = cur1 * BASE12 + tcur1;
cur2 = cur2 * BASE22 + tcur2;
cur3 = cur3 * BASE32 + tcur3;
//printf("
");
}
/*printf("cur1=%llu
", cur1);
printf("cur2=%llu
", cur2);
printf("cur3=%llu
", cur3);*/
if(MAP.count(cur1)) {
vector < pair<ull, ull> > vec = MAP[cur1];
for(auto i : vec) {
if(i.first == cur2 && i.second == cur3)
return 1;
}
}
return 0;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
scanf("%d%d%d%d", &n, &m, &a, &b);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j)
scanf("%1d", &g[i][j]);
}
for(int i = 0; i < n; ++i)
init1(i);
for(int j = 0; j + b <= m; ++j)
init2(j);
for(int i = 0; i + a <= n; ++i) {
for(int j = 0; j + b <= m; ++j) {
insert(i, j);
/*printf("i=%d j=%d haha1=%llu
", i, j, haha1[i][j]);
printf("i=%d j=%d haha2=%llu
", i, j, haha2[i][j]);
printf("i=%d j=%d haha3=%llu
", i, j, haha3[i][j]);
printf("
");*/
}
//printf("
");
}
int t;
scanf("%d", &t);
while(t--) {
printf("%d
", find());
}
}
实验证明reserve一个填充70%的哈希表可以加速25%左右。
对于一个1e6个元素的哈希表,使用4e9的unsigned int可能足够了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ull;
unordered_set<ull>MAP;
int n, m, a, b;
int g[1005][1005];
ull ha1[1005][1005];
const ull BASE1 = 23333ll;
const ull BASE12 = 2333388ll;
ull qpow(ull x, int n) {
ull res = 1;
while(n) {
if(n & 1)
res = res * x;
x = x * x;
n >>= 1;
}
return res;
}
void init1(int i) {
ull p1 = qpow(BASE1, b);
ull cur1 = 0;
for(int j = 0; j < b; ++j) {
cur1 = cur1 * BASE1 + g[i][j];
}
ha1[i][0] = cur1;
for(int j = b; j < m; ++j) {
cur1 = cur1 * BASE1 + g[i][j];
cur1 = cur1 - g[i][j - b] * p1;
ha1[i][j - b + 1] = cur1;
}
}
ull haha1[1005][1005];
void init2(int j) {
ull p1 = qpow(BASE12, a);
ull cur1 = 0;
for(int i = 0; i < a; ++i) {
cur1 = cur1 * BASE12 + ha1[i][j];
}
haha1[0][j] = cur1;
for(int i = a; i < n; ++i) {
cur1 = cur1 * BASE12 + ha1[i][j];
cur1 = cur1 - ha1[i - a][j] * p1;
haha1[i - a + 1][j] = cur1;
}
}
void insert(int si, int sj) {
ull cur1 = haha1[si][sj];
MAP.insert(cur1);
}
bool find() {
ull cur1 = 0;
int cur;
for(int i = 0; i < a; ++i) {
ull tcur1 = 0;
for(int j = 0; j < b; ++j) {
scanf("%1d", &cur);
tcur1 = tcur1 * BASE1 + cur;
}
cur1 = cur1 * BASE12 + tcur1;
}
if(MAP.count(cur1))
return 1;
return 0;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
scanf("%d%d%d%d", &n, &m, &a, &b);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j)
scanf("%1d", &g[i][j]);
}
for(int i = 0; i < n; ++i)
init1(i);
for(int j = 0; j + b <= m; ++j)
init2(j);
MAP.reserve(2000000);
for(int i = 0; i + a <= n; ++i) {
for(int j = 0; j + b <= m; ++j)
insert(i, j);
}
int t;
scanf("%d", &t);
while(t--)
printf("%d
", find());
}