题意
给定
N
,
M
,
T
,
P
,
Q
N,M,T,P,Q
N,M,T,P,Q
对于只包含
0
0
0和
∗
*
∗的二维字符数组,给定一个
N
∗
M
N*M
N∗M的矩阵,有
T
T
T次询问,每次询问一个
P
∗
Q
P*Q
P∗Q的矩阵是否是其子矩阵
题解
可以用二维哈希来做。
有关知识参考二维哈希
这道题目卡常情况非常严重,我的AC代码跑了2766ms/3000ms
如果有更好的解法请告知
另外:我一开始是将所有主矩阵中所有
p
∗
q
p*q
p∗q的子矩阵的哈希值全扔进了set里面,然后查询的,明显地,由于set的插入是
l
o
g
n
logn
logn的,会超时。
所以,我们采用将模式串的哈希值存下来,共有
T
T
T个,在其中查找所有主矩阵中所有
p
∗
q
p*q
p∗q的子矩阵的哈希值。值得注意的是,可能会出现相同的模式串,所以我后来使用的是multiset。
代码如下:
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<set>
#define ull unsigned long long
using namespace std;
const int maxn = 1010;
const ull m1=133331;
const ull m2=233;
int T;
int n,m,p,q;
char a[maxn][maxn],b[55][55];
ull hasha[maxn][maxn],hashb[55][55];
ull pow1[maxn],pow2[maxn];
multiset<ull> se;
int main(){
int cnt=0;
pow1[0]=pow2[0]=1;
for(int i=1;i<=1001;i++)pow1[i]=pow1[i-1]*m1,pow2[i]=pow2[i-1]*m2;
while(scanf("%d%d%d%d%d",&n,&m,&T,&p,&q)!=EOF){
int ans=0;
if(!n&&!m&&!T&&!p&&!q){
break;
}
getchar();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%c",&a[i][j]);
}
getchar();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
hasha[i][j]=hasha[i][j-1]*m1+a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
hasha[i][j]+=hasha[i-1][j]*m2;
}
}
for(int t=0;t<T;t++){
getchar();
for(int i=1;i<=p;i++){
for(int j=1;j<=q;j++){
scanf("%c",&b[i][j]);
}
getchar();
}
for(int i=1;i<=p;i++){
for(int j=1;j<=q;j++){
hashb[i][j]=hashb[i][j-1]*m1+b[i][j];
}
}
for(int i=1;i<=p;i++){
for(int j=1;j<=q;j++){
hashb[i][j]+=hashb[i-1][j]*m2;
}
}
se.insert(hashb[p][q]);
}
for(int i=p;i<=n;i++){
for(int j=q;j<=m;j++){
se.erase(hasha[i][j]-hasha[i][j-q]*pow1[q]-
hasha[i-p][j]*pow2[p]+hasha[i-p][j-q]*pow1[q]*pow2[p]);
}
}
printf("Case %d: %d\n",++cnt,T-se.size());
se.clear();
}
return 0;
}