UVA 11019 Matrix Matcher(雜湊)
阿新 • • 發佈:2019-01-01
題意
給定一個 \(n\times m\) 的矩陣,在給定一個 \(x\times y\) 的小矩陣,求小矩陣在大矩陣中出現的次數。
\(1 \leq n,m \leq 1000\)
\(1\leq x,y \leq 100\)
思路
做法比較顯然,先對大矩陣雜湊,在每個位上確定一個“位權”,\(Base^k\) ,對於矩陣的 \((x,y)\) 位置,可以令 \(k=(x-1)*m+y-1\) ,然後求二維字首和。接下來把小矩陣放在大矩陣的 \((1,1)(x,y)\) 位置雜湊,將雜湊值進行比較。接下來考慮的就是移動矩陣雜湊值的變化,不難發現,因為 \((1,1)\) 的位權是 \(1\)
關於雜湊的基數和模數的取值,首先基數 \(Base\) 要大於不同元素的個數,模數儘量取大質數,最好是孿生的,但注意 \(1e9+7,1e9+9\) 由於太大眾,不免會被卡,我個人習慣再取一個 \(19260817\) 。然後 \(101111,101113,101117,101119\) 也是挺好記的質數,在用鏈式雜湊表的時候可以當一維陣列下標。
程式碼
#include<bits/stdc++.h> #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i) #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i) typedef long long LL; using namespace std; const int Base[3]={29,31,37}; const int Mod[3]={(int)1e9+7,(int)1e9+9,1926081}; const int N=1005; char A[N][N],B[N][N]; LL pB[3][N*N]; LL s[3][N][N],h[3]; int n,m,p,q; inline int Hs(int x,int y){return (x-1)*m+y-1;} LL S(int k,int X1,int Y1,int X2,int Y2) { return ( (s[k][X2][Y2]-s[k][X1-1][Y2]-s[k][X2][Y1-1]+s[k][X1-1][Y1-1]) %Mod[k]+Mod[k] )%Mod[k]; } int main() { FOR(k,0,2){pB[k][0]=1;FOR(i,1,N*N-1)pB[k][i]=pB[k][i-1]*Base[k]%Mod[k];} int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); FOR(i,1,n)scanf("%s",A[i]+1); scanf("%d%d",&p,&q); FOR(i,1,p)scanf("%s",B[i]+1); if(p>n||q>m){puts("0");continue;} FOR(k,0,2)FOR(i,1,n)FOR(j,1,m) s[k][i][j]=( (s[k][i][j-1]+s[k][i-1][j]-s[k][i-1][j-1]+(A[i][j]-'a'+1)*pB[k][Hs(i,j)]) %Mod[k]+Mod[k] )%Mod[k]; FOR(k,0,2) { h[k]=0; FOR(i,1,p)FOR(j,1,q)h[k]=(h[k]+(B[i][j]-'a'+1)*pB[k][Hs(i,j)])%Mod[k]; } int cnt=0; FOR(i,1,n-p+1)FOR(j,1,n-q+1) { bool flag=1; FOR(k,0,2)if( h[k]*pB[k][Hs(i,j)]%Mod[k]!=S(k,i,j,i+p-1,j+q-1) )flag=0; if(flag)cnt++; } printf("%d\n",cnt); } return 0; }