用随机生成函数生成一个1e6的0/1矩阵,给定一个1e3的0/1矩阵,要求输出该矩阵在原矩阵中的位置。题目保证小矩阵一定是大矩阵的一部分。
解法:这题很显然是让我们思考如何在时限内配到该矩阵。一个常用的思路是处理小矩阵每个(x, y)位置的键值,全部放到哈希表中(代码里用的是 1*64 的二进制数存每个键值)。这种方法在DNA序列匹配中经常用到,即k-mer。这样,1e6的大矩阵中,只需要匹配大约(1e6*1e6)/(1e3*1e3)个位置即可,每个位置提取1*64的键值,如果该键值在哈希表中出现了,枚举每个可能的位置,通过相对位置就可以判断出可能出现的小矩阵左上角坐标,再check一下是不是要找的小矩阵即可。
注:贴上的代码hash函数用的vector存同一个哈希值的每个位置。但在第一次过的时候,考虑到样例只有三组,所以代码没有处理小矩阵生成的所有64位键值存在相同的情况,也可以AC。在键值配上的时候随手check了一下,删掉check函数还是会WA的。
吐槽:交map T了一发,发现其实map只用到了hash的功能,于是随手改了unorder_map,但本地编译器版本太低编译不了,交了一发居然过了。一脸懵逼。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=1000;
const int M=1000000;
int T;
char s[1005][1005];
unordered_map<unsigned long long,vector<pii> > mp;
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;
}
inline unsigned long long val(int i,int j) {
unsigned long long ret=0;
for (int x=0;x<64;++x)
ret=(ret<<1)+(s[i][j+x]-'0');
return ret;
}
inline unsigned long long Hash(int i,int j) {
unsigned long long ret=0;
for (int x=0;x<64;++x)
ret=(ret<<1)+f(i,j+x);
return ret;
}
inline bool check(int x,int y) {
if (x<0||x>M||y<0||y>M)
return false;
for (int i=1;i<=1000;++i)
for (int j=1;j<=1000;++j)
if (f(i+x-1,j+y-1)!=(s[i][j]-'0'))
return false;
return true;
}
int _main()
{
freopen("data.in","w",stdout);
puts("1");
for (int i=937;i<1000+937;++i) {
for (int j=0;j<1000;++j)
putchar(f(i+1,j+1)+'0');
putchar('\n');
}
return 0;
}
int main()
{
scanf("%d",&T);
for (int cas=1;cas<=T;++cas) {
for (int i=1;i<=N;++i)
scanf("%s",s[i]+1);
for (int i=1;i<=N;++i)
for (int j=1;j<=N-63;++j)
mp[val(i,j)].push_back(pii(i,j));
for (int i=0;i<=M;i+=N) {
int flag=0;
for (int j=937;j<=M;j+=N-63) {
unsigned long long key=Hash(i,j);
if (mp.find(key)==mp.end())
continue;
vector<pii> &pos=mp[key];
for (int k=0;k<(int)pos.size();++k) {
int x=i-pos[k].first+1,y=j-pos[k].second+1;
if (check(x,y)) {
flag=1;
printf("Case #%d :%d %d\n",cas,x,y);
break;
}
}
}
if (flag)
break;
}
}
return 0;
}