Problem
106×106
的 01 矩阵(记作 A )根据下列提供函数给定,f(x, y) 表示该矩阵的 x 行 j 列的数
inline unsigned sfr(
unsigned h,
unsigned x) {
return h >> x;
}
int f(LL i, LL j) {
LL w = i *
1000000ll + j;
int h =
0;
for(
int k =
0; k <
5; ++k) {
h += (
int) ((w >> (
8 * k)) &
255);
h += (h <<
10);
h ^= sfr(h,
6);
}
h += h <<
3;
h ^= sfr(h,
11);
h += h <<
15;
return sfr(h,
27) &
1;
}
提供
1000×1000
的矩阵 B ,要求判断其在 A 矩阵中的位置。
Idea
由于 A 矩阵过大,纵然想要先行获取其每位的数值,在时间复杂度内也是不允许的。
考虑将 B 矩阵按
8×8
的矩阵样式获取其每个子矩阵(总数近
106
个)的 hash 值,并记录。
将 A 矩阵严格划分为
1000×1000
的子矩阵
subA
(共
1000×1000
个)。
则获取每个
subA
的左上
8×8
和右下
8×8
,必然至少存在一个恰好与 B 矩阵中的
8×8
矩阵的 hash 值相同。
对获取到的矩阵判断其是否与 B 矩阵完全相同即可(也可不必判断,由于 A 矩阵完全随机,故碰撞的概率很小)。
Code
#include<bits/stdc++.h>
using namespace std;
const int N =
1e6 +
10;
const int HASH_SEED =
1999997;
int T, ica =
1;
unsigned long long num, g[HASH_SEED];
char b[
1010][
1010];
int b8[
1010][
1010], x[HASH_SEED], y[HASH_SEED];
void HASH(
int i,
int j) {
int hash = num % HASH_SEED;
while(g[hash]) {
if(++hash == HASH_SEED) hash =
0;
}
g[hash] = num;
x[hash] = i;
y[hash] = j;
}
inline unsigned sfr(
unsigned h,
unsigned x) {
return h >> x;
}
int f(
long long i,
long long j) {
long long w = i *
1000000ll + j;
int h =
0;
for(
int k =
0; k <
5; ++k) {
h += (
int) ((w >> (
8 * k)) &
255);
h += (h <<
10);
h ^= sfr(h,
6);
}
h += h <<
3;
h ^= sfr(h,
11);
h += h <<
15;
return sfr(h,
27) &
1;
}
bool jug(
int x,
int y) {
if(x <=
0 || y <=
0)
return false;
for(
int i=
0;i<
1000;i++)
for(
int j=
0;j<
1000;j++)
if(f(x+i, y+j) != b[i+
1][j+
1]-
'0')
return false;
return true;
}
bool solveHash(
int i,
int j) {
num =
0;
for(
int ii=
0;ii<
8;ii++)
for(
int jj=
0;jj<
8;jj++)
{
num <<=
1;
num += f(i+ii, j+jj);
}
int hash = num % HASH_SEED;
while(g[hash]) {
if(g[hash] == num) {
printf(
"Case #%d :%d %d\n", ica++, i-x[hash]+
1, j-y[hash]+
1);
return true;
}
if(++hash == HASH_SEED) hash =
0;
}
return false;
}
void solve() {
for(
int i=
1;i<
1000000;i+=
1000)
for(
int j=
1;j<
1000000;j+=
1000)
if(solveHash(i, j) || solveHash(i+
1000-
7, j+
1000-
7))
return;
}
int main()
{
scanf(
"%d", &T);
while(ica <= T)
{
memset(g,
0,
sizeof(g));
for(
int i=
1;i<=
1000;i++)
{
scanf(
" %s", b[i]+
1);
num =
0;
for(
int j=
1;j<=
7;j++) num<<=
1, num += b[i][j]-
'0';
for(
int j=
8;j<=
1000;j++)
{
num<<=
1, num+=b[i][j]-
'0';
num %=
256;
b8[i][j-
7] = num;
}
}
for(
int i=
1;i<=
1000-
7;i++)
for(
int j=
1;j<=
1000-
7;j++)
{
num =
0;
for(
int k=
0;k<
8;k++)
num<<=
8, num += b8[i+k][j];
HASH(i, j);
}
solve();
}
}