BZOJ 2462 (二维hash学习)
-
二维hash
创建两个种子 b a s e 1 , b a s e 2 base1,base2 base1,base2 创建一个 无符号 64 64 64 位数组 h a s h a hasha hasha
先对每一行做前缀 h a s h hash hash 值
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) hasha[i][j] = hasha[i][j - 1] * base1 + a[i][j];
再做 1 , 1 ∼ i , j 1,1 \sim i,j 1,1∼i,j 的 h a s h hash hash 值
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) hasha[i][j] += hasha[i - 1][j] * base2;
二维 h a s h hash hash 值 = = = 当前行的前缀到 j j j 的 h a s h hash hash 值 + + + 前 i − 1 i - 1 i−1 行 h a s h hash hash 值
查询:
hasha[i][j] - hasha[i][j - y]*pow1[y] - hasha[i - x][j]*pow2[x] + hasha[i - x][j - y]*pow1[y]*pow2[x]
查询的是 i ≥ x i \geq x i≥x j ≥ y j \geq y j≥y 时 矩形大小为 x , y x,y x,y 的 h a s h hash hash 值 , h a s h [ i ] [ j ] hash[i][j] hash[i][j] 是右下角坐标二维前缀 h a s h hash hash 值
-
题目
-
代码
int ans, cas = 0; pow1[0] = pow2[0] = 1; for (int i = 1; i <= 1001; i++) pow1[i] = pow1[i - 1] * base1, pow2[i] = pow2[i - 1] * base2; scanf("%d %d %d %d", &n, &m, &x, &y); v.clear(); for (int i = 1; i <= n; i++) scanf("%s", a[i] + 1); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) hasha[i][j] = hasha[i][j - 1] * base1 + a[i][j]; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) hasha[i][j] += hasha[i - 1][j] * base2; for (int i = x; i <= n; i++) for (int j = y; j <= m; j++) v.push_back(hasha[i][j] - hasha[i][j - y]*pow1[y] - hasha[i - x][j]*pow2[x] + hasha[i - x][j - y]*pow1[y]*pow2[x]); // 从 x,y开始保证矩形大小不小于x,y sort(v.begin(), v.end()); int t; scanf("%d", &t); while (t--) { for (int i = 1; i <= x; i++) scanf("%s", b[i] + 1); for (int i = 1; i <= x; i++) for (int j = 1; j <= y; j++) hashb[i][j] = hashb[i][j - 1] * base1 + b[i][j]; for (int i = 1; i <= x; i++) for (int j = 1; j <= y; j++) hashb[i][j] += hashb[i - 1][j] * base2; int pos = lower_bound(v.begin(), v.end(), hashb[x][y]) - v.begin(); if (pos == v.size()){ puts("0"); continue; } if (v[pos] == hashb[x][y]) puts("1"); else puts("0"); }
-
题型
二维 h a s h hash hash