Matrix(二维hash)

题目链接

题目

给定一个M行N列的01矩阵(只包含数字0或1的矩阵),再执行Q次询问,每次询问给出一个A行B列的01矩阵,求该矩阵是否在原矩阵中出现过。

分析

把原矩阵的a ( b的大小的矩阵用hash值算出来,在把查询的矩阵hash值算出来与原矩阵的hash值比较是否出现过就ok了

虽然这个题比较模板,但是本弱弱还是说说

按照一维的写法,把二维变成一维不久解决了,但是怎么去算原矩阵中的 A * B矩阵大小的hash值才是难点

思路:其实就是先Z字把矩阵链接起来就行,然后算到有多的减去就行

其他正规一点的方法

细节在代码说

另外这个题我cin被卡了

参考

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<cstdio>
#include<cstring>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
using namespace std;
const int maxn = 1005;
char ch[maxn][maxn],tmp[maxn]; //原矩阵,查找矩阵
int n,m,a,b,q;
int p = 131;   //据大佬们的经验,这个素数一般取131或者13331
ll hashv[maxn][maxn],power[maxn * maxn]; //原矩阵的hash值,power[k]存储 P^k mod 2^64
set <ll> Hash;

//求原矩阵的hash
void calHash() 
{
	for(int i = 1 ; i <= n ; i++){
		for(int j = 1 ; j <= m ; j++){
			hashv[i][j] = hashv[i][j - 1] * p + ch[i][j] - '0';
		}
	}
	power[0] = 1;
	for(int  i = 1 ; i <= n * m ; i++){
		power[i] = power[i - 1] * p;
	}
}

//获取子串 l ~ r 的hash值
ll get_hash(ll f[] , int l,int r) 
{
	return f[r] - f[l - 1] * power[r - l + 1];
}

int main(){
	scanf("%d%d%d%d",&n,&m,&a,&b);
	for(int i = 1 ; i <= n ; i++) scanf("%s", ch[i] + 1);
	calHash();
    //求原矩阵中a * b大小的矩阵hash值
	for(int i = b ; i <= m ; i++){  
		ll s = 0; //目前的hash值
		int l = i - b + 1,r = i;
		for(int j = 1 ; j <= n ; j++){
            //一行一行的算,然后上一行末尾接下一行的开始就变成一维的了
            //为什么乘以power[b],多想想就明白了
			s = s * power[b] + get_hash(hashv[j],l,r); 
            // 减去多余的
            //多余的想理解清楚,请借助参考
			if(j > a) s -= get_hash(hashv[j - a],l,r) * power[a * b]; 
			if(j >= a) Hash.insert(s); 
		}
	}
	scanf("%d",&q);
	while(q--){
		ll s = 0;
		for(int i = 1 ; i <= a ; i++){
			scanf("%s",tmp + 1);
			for(int j = 1 ; j <= b ; j++){
				s = s * p + tmp[j] - '0';
			}
		}
		if(Hash.count(s)) puts("1");
		else puts("0");
	}
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值