AOJ 1312 ICPC Asia resional 2010 Problem H: Where's Wally
問題
nxmマスの各マスが0または1のグリッドimageが与えられる。
pxpマスの各マスが0または1のグリッドpatternが与えられる。
imageの中にpatternはいくつ含まれるか求めよ。
patternが別の箇所に現れた場合、それらは別々にカウントする。
patternは上下左右の反転、90度単位の回転を何度してもよい。
制約条件
n,m≦1000
p≦100
方針
二次元でrolling hashを計算する。
imageの点(i,j)からpxpマスを切り取った部分のrolling hashと、patternのrolling hashが一致するかを見てやればよい。
ソースコード
int w,h,p; ll hash[1001][1001],tmp[101][101],base[1001][1001]; bool img[1000][1000],ptn[100][100],ptn2[100][100]; char in[1001]; void mirror(){ rep(i,p)rep(j,p/2)swap(ptn[i][j],ptn[i][p-1-j]); } void rot(){ rep(i,p)rep(j,p)ptn2[i][j]=ptn[i][j]; rep(i,p)rep(j,p)ptn[i][j]=ptn2[p-1-j][i]; } inline int calcbit(char c){ int bit; if('A'<=c&&c<='Z')bit=c-'A'; else if('a'<=c&&c<='z')bit=c-'a'+26; else if('0'<=c&&c<='9')bit=c-'0'+52; else if(c=='+')bit=62; else if(c=='/')bit=63; else assert(0); return bit; } int main() { base[0][0]=1; const ll tate=1000000007, yoko=7; rep(i,1000)rep(j,1000)if(i||j) base[i][j]=i?base[i-1][j]*tate:base[i][j-1]*yoko; while(scanf("%d%d%d ",&w,&h,&p),w){ memset(img,0,sizeof(img)); rep(i,h){ fgets(in,1000,stdin); rep(j,(w-1)/6+1){ int bit=calcbit(in[j]); rep(k,6)img[i][j*6+k]=bit&1<<5-k; //debug!!! } } rep(i,p){ fgets(in,1000,stdin); rep(j,(p-1)/6+1){ int bit=calcbit(in[j]); rep(k,6)ptn[i][j*6+k]=bit&1<<5-k; } } rep(i,h)rep(j,w){ hash[i+1][j+1]=(img[i][j]+1)*base[i][j]+hash[i][j+1]+hash[i+1][j]-hash[i][j]; } set<ll> patterns; rep(it,8){ memset(tmp,0,sizeof(tmp)); rep(i,p)rep(j,p){ tmp[i+1][j+1]=(ptn[i][j]+1)*base[i][j]+tmp[i][j+1]+tmp[i+1][j]-tmp[i][j]; } patterns.insert(tmp[p][p]); rot(); if(it==3)mirror(); } vector<ll> pattern(all(patterns)); int ans=0; rep(i,h-p+1)rep(j,w-p+1){ ll tmp=hash[i+p][j+p]-hash[i][j+p]-hash[i+p][j]+hash[i][j]; rep(k,pattern.size()){ ll tmp2=pattern[k]*base[i][j]; if(tmp==tmp2)ans++; } } printf("%d\n",ans); } return 0; }