HDU 6046 hash 哈希

用随机生成函数生成一个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 
using namespace std;
typedef pair pii;
const int N=1000;
const int M=1000000;
int T;
char s[1005][1005];
unordered_map > 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 &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;
}

你可能感兴趣的:(acm)