题意
传送门 AOJ 1312
题解
使用二维滚动哈希计算得到图片中所有 p × p p\times p p×p 的子阵哈希值,以及旋转、镜面翻转共 2 × 4 2\times 4 2×4 种模式子阵的哈希值,枚举各位置进行匹配即可。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 1005
typedef unsigned long long ull;
int w, h, p, id[128], image[maxn][maxn], pattern[maxn][maxn], pattern2[maxn][maxn];
ull _hash[maxn][maxn], tmp[maxn][maxn], rec[8];
void compute_hash(int mat[maxn][maxn], int n, int m)
{
const ull B1 = 9973, B2 = 1000000007;
ull t1 = 1;
for (int j = 0; j < p; j++)
t1 *= B1;
for (int i = 0; i < n; i++)
{
ull e = 0;
for (int j = 0; j < p; j++)
e = e * B1 + mat[i][j];
for (int j = 0; j + p <= m; j++)
{
tmp[i][j] = e;
if (j + p < m)
e = e * B1 - mat[i][j] * t1 + mat[i][j + p];
}
}
ull t2 = 1;
for (int i = 0; i < p; i++)
t2 *= B2;
for (int j = 0; j + p <= m; j++)
{
ull e = 0;
for (int i = 0; i < p; i++)
e = e * B2 + tmp[i][j];
for (int i = 0; i + p <= n; i++)
{
_hash[i][j] = e;
if (i + p < n)
e = e * B2 - tmp[i][j] * t2 + tmp[i + p][j];
}
}
}
void read(int mat[maxn][maxn], int h, int w)
{
for (int i = 0; i < h; i++)
{
char s[maxn];
scanf(" %s", s);
int j = 0, k = 0;
while (j < w)
{
for (int d = 5; d >= 0; d--)
{
int f = (id[s[k]]) >> d & 1;
mat[i][j++] = f;
if (j >= w)
break;
}
++k;
}
}
}
int main()
{
id['A'] = 0, id['a'] = 26, id['0'] = 52, id['+'] = 62, id['/'] = 63;
for (int i = 'B'; i <= 'Z'; i++)
id[i] = id[i - 1] + 1;
for (int i = 'b'; i <= 'z'; i++)
id[i] = id[i - 1] + 1;
for (int i = '1'; i <= '9'; i++)
id[i] = id[i - 1] + 1;
while (~scanf("%d%d%d", &w, &h, &p) && (w | h | p))
{
read(image, h, w);
read(pattern, p, p);
for (int k = 0; k < 8; k++)
{
// 旋转
for (int i = 0; i < p; i++)
{
for (int j = 0; j < p; j++)
{
pattern2[i][j] = pattern[j][p - 1 - i];
}
}
compute_hash(pattern2, p, p);
rec[k] = _hash[0][0];
if (k == 3)
{
// 镜面翻转
for (int i = 0; i < p; i++)
{
for (int j = 0; j < p; j++)
{
pattern[i][j] = pattern2[i][p - 1 - j];
}
}
}
else
{
for (int i = 0; i < p; i++)
{
for (int j = 0; j < p; j++)
{
pattern[i][j] = pattern2[i][j];
}
}
}
}
// 模式匹配
int res = 0;
compute_hash(image, h, w);
for (int i = 0; i + p <= h; i++)
{
for (int j = 0; j + p <= w; j++)
{
for (int k = 0; k < 8; k++)
{
if (rec[k] == _hash[i][j])
{
++res;
break;
}
}
}
}
printf("%d\n", res);
}
return 0;
}