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; }