P10474 [ICPC 2011 Beijing R] Matrix 矩阵哈希

题意分析

有一个01构成的大矩阵,还有一些小矩阵,问小矩阵在大矩阵中是否出现过。

求解思路

(1)暴力匹配 时间复杂度太高
(2)利用hash计算,大矩阵中每一个A*B的小矩阵的hash值,再与每一个小矩阵的hash值匹配,若有相等的,即证明找到了相同的。

原矩阵 (M×N) → 预处理所有 A×B 子矩阵的哈希值 → 存入map

查询矩阵 (A×B) → 计算查询矩阵的哈希值 → 在map中查找 → 输出结果

关键点:如何在大矩阵中计算每一个A*B的小矩阵的hash值?

这是一个二维hash的计算啊, 这时你想到了什么?是不是跟二位前缀和很像啊,借助二维前缀和的思想来解决这道题。

第一步:先计算行方向的hash值。

行方向哈希(一维前缀哈希)

cpp 复制代码
Hash[i][j] = Hash[i][j-1] × BASE1 + a[i][j]

Hashij 表示第 i 行前 j 个字符的哈希值。

第二步:再上一步的基础上,计算列方向的hash值。

这时 Hashij 表示从 (1,1) 到 (i,j) 的矩形哈希值

cpp 复制代码
Hash[i][j] = Hash[i-1][j] × BASE2 + Hash[i][j] (行哈希值)

这里为了避免冲突,行和列和BASE选择了不同的

第三步:计算A*B的子矩阵的hash值。

容斥原理

子矩阵的hash值 = Hashij - Hashi-Aj × Base2A - Hashij-B × Base1B + Hashi-Aj-B × Base2A × Base1B

BASE2a 的作用:将上面部分的权重"提升"到正确的位置

BASE1b 的作用:将左面部分的权重"提升"到正确的位置
记住: 哈希公式中的每个幂次都是为了"对齐权重",让减法和加法能够正确进行!

代码实现

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const unsigned long long p1=131,p2=139;
const int N=1009;
unsigned long long h[N][N],h1[N][N],pow1[N],pow2[N];
int c[N][N],d[N][N];
map<ULL,bool>mapp;
int main()
{
	int a,b,n,m;
	cin>>n>>m>>a>>b;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%1d",&c[i][j]);
		}
	}
	//1.计算每行的hash值 
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			h[i][j]=h[i][j-1]*p1+c[i][j];
             
		}
	}
	//2.计算(1,1)到(i,j)的hash值
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			h[i][j]=h[i-1][j]*p2+h[i][j];
		}
	} 
	//3.预处理pow1,pow2的值。
	pow1[0]=pow2[0]=1; 
	for(int i=1;i<=n;i++)  pow1[i]=pow1[i-1]*p1;
	for(int i=1;i<=m;i++)  pow2[i]=pow2[i-1]*p2;
	//4.预处理出大矩阵中每一个A*B的小矩阵hash值,用map记录
	for(int i=a;i<=n;i++)
	{
		for(int j=b;j<=m;j++)
		{
			ULL res=h[i][j]-h[i-a][j]*pow2[a]-h[i][j-b]*pow1[b]+h[i-a][j-b]*pow2[a]*pow1[b];
		    mapp[res]=1;
		}
	 } 
	 //5.查询hash值是否存在
	 int q;
	 cin>>q;
	 while(q--)
	 {
	 	ULL ans=0;
	 	for(int i=1;i<=a;i++)
		{
			for(int j=1;j<=b;j++)
			{
				scanf("%1d",&d[i][j]);
			}
		}
		for(int i=1;i<=a;i++)
          for(int j=1;j<=b;j++)
            h1[i][j]=h1[i][j-1]*p1+d[i][j];
        for(int i=1;i<=a;i++)
          for(int j=1;j<=b;j++)
            h1[i][j]=h1[i-1][j]*p2+h1[i][j];
        
        ans=h1[a][b];
		if(mapp[ans])  cout<<"1"<<endl;
		else cout<<"0"<<endl;
	  } 
	 
 } 

我的bug

bug1:读入,01矩阵我用cin读的,读入错误

方法一:

cpp 复制代码
string s;
cin >> s;
c[i][j] = s[j-1] - '0';

方法二:

cpp 复制代码
scanf("%1d",&d[i][j]);

bug2:pow10没有初始化

cpp 复制代码
pow1[0]=pow2[0]=1; 
for(int i=1;i<=n;i++)  pow1[i]=pow1[i-1]*p1;
for(int i=1;i<=m;i++)  pow2[i]=pow2[i-1]*p2;
相关推荐
海兰21 小时前
【高速缓存】RedisVL 存储类型选择指南:Hash 与 JSON
人工智能·redis·算法·缓存·json·哈希算法
稚南城才子,乌衣巷风流21 小时前
树哈希(Tree Hashing)原理与应用详解
算法·elasticsearch·哈希算法
bj_zhb1 天前
矩阵的白化变换/球化变换
线性代数·矩阵
海兰1 天前
【高速缓存】 RedisVL MCP 运行指南(下)
人工智能·redis·哈希算法·高速缓存
酉鬼女又兒2 天前
[特殊字符]零基础入门AI:归纳演绎、假设空间、归纳偏好、NFL、过拟合与欠拟合、模型评估选择、超参数、性能度量、混淆矩阵、P-R曲线和F1
人工智能·windows·python·深度学习·安全·机器学习·矩阵
2601_955759622 天前
如何用 Claude Opus 5 API 写出结构清晰的 SEO 文章
线性代数·矩阵
2601_955759623 天前
Claude Opus 5 SEO 实战:打造高质量长尾关键词内容矩阵
线性代数·矩阵
科技大视界3 天前
TikTok广告素材投放工具:从官方后台到AIGC一体化矩阵构建高效投放矩阵
人工智能·矩阵·aigc
jinyishu_3 天前
哈希表原理与开放定址法C++实现
c++·哈希算法·散列表
闪电悠米3 天前
力扣hot100-54.螺旋矩阵-模拟边界控制详解
算法·leetcode·矩阵