题目大意
给出一个n * m的矩阵,矩阵中只有一些*或者0
n <= 1000, m <= 1000
然后有t (t <= 100)个询问,每次询问给出一个p * q的矩阵
p,q是提前固定的数值。
问这些询问中能是大矩阵的子矩阵的有几个
Sample Input
3 3 2 2 2
*00
0**
*00
**
00
*0
**
3 3 2 2 2
*00
0**
*00
**
00
*0
0*
0 0 0 0 0
Sample Output
Case 1: 1
Case 2: 2
解题思路
因为小矩阵的长宽都给定了,所以可以直接 O(n2) 预处理出大矩阵中每个p*q的小矩阵的哈希值(最多n*m个)放入哈希表中,再用给的小矩阵查询即可。
预处理时先用pre[i][j]处理出第i行前j的字符的哈希值,再算出每个位置开始q个字符的哈希值,然后用sum[i][j]处理1至i行从第j个字符开始q个字符的哈希值,也就是前缀和,最后用两个前缀和相减(sum[i][j]-sum[i][j-p]*pow[p*c])即为以第i-r+1行第j个字符为左上角的p*q的矩阵的哈希值了。
注意哈希表模数要取6位以上的素数(999997,233333),不然要超时,亲身经历,wu~~~~
时间复杂度 O(n2)
这里写代码片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#define ll unsigned long long
using namespace std;
int getint()
{
int i=0 ,f=1;char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=1005,p=3,H=999997;
char s[N];
int T,n,m,q,r,c,ans;
ll cf[2505],pre[N][N],sum[N][N],val[N*N];
int tot,hsh[H+5],nxt[N*N];
void insert(ll x)
{
int y=x%H;
for(int v=hsh[y];v;v=nxt[v])
if(val[v]==x)return;
nxt[++tot]=hsh[y],hsh[y]=tot,val[tot]=x;
return;
}
void find(ll x)
{
int y=x%H;
for(int v=hsh[y];v;v=nxt[v])
if(val[v]==x)
{
ans++;
return;
}
return;
}
void Init()
{
memset(hsh,0,sizeof(hsh));
memset(pre,0,sizeof(pre));
memset(sum,0,sizeof(sum));
memset(cf,0,sizeof(cf));
ans=tot=0;
ll x;
m=getint(),q=getint(),r=getint(),c=getint();
cf[0]=1;
for(int i=1;i<=r*c;i++)cf[i]=cf[i-1]*p;
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
if(s[j]=='0')pre[i][j]=pre[i][j-1]*p;
else pre[i][j]=pre[i][j-1]*p+1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m-c+1;j++)
{
sum[i][j]=pre[i][j+c-1]-pre[i][j-1]*cf[c];
sum[i][j]=sum[i-1][j]*cf[c]+sum[i][j];
}
}
for(int i=r;i<=n;i++)
for(int j=1;j<=m-c+1;j++)
{
x=sum[i][j]-sum[i-r][j]*cf[r*c];
insert(x);
}
}
void solve()
{
ll x=0;
for(int i=1;i<=r;i++)
{
scanf("%s",s+1);
for(int j=1;j<=c;j++)
{
if(s[j]=='0')x=x*p;
else x=x*p+1;
}
}
find(x);
}
int main()
{
//freopen("lx.in","r",stdin);
while(n=getint())
{
if(n==0)break;
Init();
while(q--)
solve();
cout<<"Case "<<++T<<": "<<ans<<'\n';
}
return 0;
}