POJ3690:Constellations——题解

http://poj.org/problem?id=3690

题目大意:给一个图和几个子图,判断有多少种子图在原图出现过。

——————————————————————

二维哈希即可,操作看代码,我觉得蛮好看的。

注意这题恶心的时限。

pow预处理能少时间,读入字符用getchar不然会TLE。

用multiset查找然后再一个个erase即可,这样set前后size的差值即是答案。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<set>
using namespace std;
typedef unsigned long long ll;
const int N=1001;
const int M=1001;
const int P=51;
const int Q=51;
const ll b=2;
const ll w=1e8+7;
ll ha0[N][M];
ll ha1[P][Q];
ll qpow[2][P];
inline ll tn(char ch){
    if(ch=='0')return 0;
    return 1;
}
void init(){
    qpow[0][0]=qpow[1][0]=1;
    for(int i=1;i<P;i++){
    qpow[0][i]=qpow[0][i-1]*b;
    qpow[1][i]=qpow[1][i-1]*w;
    }
    return;
}
int main(){
    init();
    int n,m,t,p,q,casenum=0;;
    while(cin>>n>>m>>t>>p>>q){
    if(n+m+t+p+q==0)break;
    multiset<ll>app;
    casenum++;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
        char ch=getchar();
        while(ch==' '||ch=='\n')ch=getchar();
        ha0[i][j]=ha0[i][j-1]*b+tn(ch);
        }
    }
    for(int j=1;j<=m;j++){
        for(int i=1;i<=n;i++){
        ha0[i][j]+=ha0[i-1][j]*w;
        }
    }
    for(int k=1;k<=t;k++){
        for(int i=1;i<=p;i++){
        for(int j=1;j<=q;j++){
            char ch=getchar();
            while(ch==' '||ch=='\n')ch=getchar();
            ha1[i][j]=ha1[i][j-1]*b+tn(ch);
        }
        }
        for(int j=1;j<=q;j++){
        for(int i=1;i<=p;i++){
            ha1[i][j]+=ha1[i-1][j]*w;
        }
        }
        app.insert(ha1[p][q]);
    }
    for(int i=p;i<=n;i++){
        for(int j=q;j<=m;j++){
        int si=i-p,sj=j-q;
        app.erase(ha0[i][j]-ha0[si][j]*qpow[1][p]-ha0[i][sj]*qpow[0][q]+ha0[si][sj]*qpow[1][p]*qpow[0][q]);
        }
    }
    printf("Case %d: %d\n",casenum,t-(int)app.size());
    }
    return 0;
}

 

posted @ 2017-12-09 11:26  luyouqi233  阅读(236)  评论(0编辑  收藏  举报