题目
给定一个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;
}