HDU6046 hash 【2017多校联训第二场B】

传送门
题目大意:给出一个 106106 的矩阵的每一位的计算方式,然后给出一个 103103 的矩阵,求这个矩阵出现的位置。
题解:对于小矩阵的每一个位置求出这个位置以及之后 63 位的值压在一个 unsigned long long 里面。因为这个大矩阵是完全随机的,而且 264 远大于 1012 所以我们可以认为,只要压的那个64位的 unsigned long long 相同,就是同一个位置。所以我们现在已经有了一个手段,猜任意一个位置,我们能判断是不是在小矩阵中。所以我们就可以开始枚举位置。但是显然我们一个一个地枚举位置是不可取的,所以枚举是需要技巧的,我们可以以1000为基数跳着寻找下一个位置,然后总的时间复杂度就是 O((106103)264)
看不懂就看看代码吧,表达能力捉鸡……

#include <bits/stdc++.h>
const int MAXN = 1e3 + 5, MXM = 1e6;
const int L = 1e3, ZIP = 64;
#define LL unsigned long long
using namespace std;
inline unsigned sfr(unsigned h, unsigned x) {
    return h >> x;
}
inline unsigned Ran() {
    return rand() << 15 | rand();
}
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;
}
const int MOD = 1313131;
struct HashMap {
    int adj[MOD], cc, nxt[MAXN * MAXN];
    LL val[MAXN * MAXN], pos[MAXN * MAXN];
    void clr() { memset(adj, 0, sizeof adj); cc = 0; }
    inline void Ins(LL v, LL p) {
        int t = v % MOD; ++ cc;
        val[cc] = v; pos[cc] = p; nxt[cc] = adj[t]; adj[t] = cc;
    }
    inline LL Find(LL v) {
        int u = v % MOD;
        for(int i = adj[u]; i; i = nxt[i])
            if(val[i] == v) return pos[i];
        return 0;
    }
} mp;
char s[MAXN];
LL hsh[MAXN];
int main () {
    int T;
    scanf("%d", &T);
    for(int Cas = 1; Cas <= T; ++ Cas) {
        for(int i = 1; i<=L; i++) {
            scanf("%s", s+1);
            for(int j = 1; j <= L; j++) {
                hsh[j] = (hsh[j-1]<<1)+(s[j]=='1');
            }
            for(int j = 1; j<=(L-ZIP+1); j++)
                mp.Ins(hsh[j+ZIP-1], 1000001LL*i+j);
        }
        LL ans = 0; int px, py;
        for(int i = 1; (!ans) && i <= MXM; i += 1000)
            for(int j = 1; (!ans) && j <= MXM; j += 900) {
                if(j+ZIP-1 > MXM) continue ;
                LL hsh = 0;
                for(int t = 0; t<ZIP; t++)
                    hsh = (hsh<<1) + f(i, j+t);
                if((ans=mp.Find(hsh)) != 0) {
                    px = i, py = j; break;
                }
            }
        int x = ans / 1000001ull, y = ans % 1000001ull;
        printf("Case #%d :%d %d\n", Cas, px-x+1, py-y+1);
        if(Cas != T) mp.clr();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值