您的位置:首页 > 其它

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

2017-07-27 22:16 309 查看
传送门

题目大意:给出一个106∗106的矩阵的每一位的计算方式,然后给出一个103∗103的矩阵,求这个矩阵出现的位置。

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

看不懂就看看代码吧,表达能力捉鸡……

#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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: