POJ 3690

题意

给定 N , M , T , P , Q N,M,T,P,Q N,M,T,P,Q
对于只包含 0 0 0 ∗ * 的二维字符数组,给定一个 N ∗ M N*M NM的矩阵,有 T T T次询问,每次询问一个 P ∗ Q P*Q PQ的矩阵是否是其子矩阵

题解

可以用二维哈希来做。
有关知识参考二维哈希
这道题目卡常情况非常严重,我的AC代码跑了2766ms/3000ms
如果有更好的解法请告知
另外:我一开始是将所有主矩阵中所有 p ∗ q p*q pq的子矩阵的哈希值全扔进了set里面,然后查询的,明显地,由于set的插入是 l o g n logn logn的,会超时。
所以,我们采用将模式串的哈希值存下来,共有 T T T个,在其中查找所有主矩阵中所有 p ∗ q p*q pq的子矩阵的哈希值。值得注意的是,可能会出现相同的模式串,所以我后来使用的是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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值