hash HDU - 6046 hash 抽屉原理

题解

题目大意 给你一个hash函数 传入横纵坐标得到一个1e6*1e6的矩阵 给你1e3*1e3的子矩阵问在大矩阵的哪个位置 输出左上角坐标

将1*64的横条状矩阵作为一个单位(2^64足够大并且方便hash) 对小矩阵每个位置都取的单位矩阵hash 将对应位置存入hash表
根据抽屉原理 对大矩阵每隔1000行1000-63列抽取一个单位矩阵并计算hash(这样不管怎么抽都能抽到小矩阵中的一个)并用hash表找找到出现位置并输出
不手写hash表直接用unordered_map也是可以 只是没手写的快

AC代码

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 3; //素数
char s[MAXN];

struct HashTable
{
	struct node
	{
		ull key, val;
		int nxt;
	}elem[MAXN]; //存储元素
	int head[MAXN], tot; //head存储每个位置的第一个元素编号
	void Init()
	{
		tot = 0;
		memset(head, -1, sizeof(head));
	}
	void Push(ull key, ull val)
	{
		int k = key % MAXN; //取模位置
		for (int i = head[k]; ~i; i = elem[i].nxt)
			if (elem[i].key == key) //key相等
			{
				elem[i].val += val; //已有+val
				return;
			}
		elem[tot] = { key, val, head[k] }; //将原有接在后面
		head[k] = tot++; //head记录当前
	}
	ull Find(ull key)
	{
		int k = key % MAXN; //取模位置
		for (int i = head[k]; ~i; i = elem[i].nxt)
			if (elem[i].key == key) //key相等
				return elem[i].val;
		return 0;
	}
}ht;
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;
}
void solve()
{
	ht.Init();
	int n = 1e6, m = 1e3; //大小矩阵大小
	for (int i = 1; i <= m; i++)
	{
		scanf("%s", s + 1);
		ull key = 0; //将横着64个数值压缩到ull
		for (int j = 1; j < 64; j++) key = key << 1 | (s[j] == '1');
		for (int j = 64; j <= m; j++) //从第64个开始向hash表插入
		{
			key = key << 1 | (s[j] == '1');
			ht.Push(key, (i - 1) * m + j - 64); //对应key存储位置 坐标-1
		}
	}
	for (int i = 1; i <= n; i += m) //根据抽屉原理每隔一段计算一个
		for (int j = 1; j + 63 <= n; j += m - 63)
		{
			ull key = 0;
			for (int k = 0; k < 64; k++) key = key << 1 | f(i, j + k);
			int pos = ht.Find(key);
			if (pos)
			{
				cout << (i - pos / m) << " " << (j - pos % m) << endl;
				return;
			}
		}
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int T;
	cin >> T;
	for (int ti = 1; ti <= T; ti++)
		printf("Case #%d :", ti), solve();

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值