[BZOJ 1567] Blue Mary的战役地图
Link:
Solution:
矩阵Hash/二维$Hash$模板题
涉及到需要快速查询、匹配的题目,考虑直接上$Hash$
矩阵$Hash$其实就是每行先各$Hash$一次,对于$x~x+l-1$行取出$y~y+l-1$列的$Hash$值再进行一次$Hash$即可
取出$l~r$的$Hash$值的方法:$Hash[j]-Hash[i-1]*base^{j-i+1}$
注意横竖两次$Hash$乘数要不同!否则碰撞概率极高
Tip: 判断一个数是否在有序序列中的方式:$*lower\_ bound(begin,end,now)==now$
Code:
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int MAXN=55; const ull hsn1=2333333,hsn2=1234567; int n,dat[2][MAXN][MAXN]; ull pre[MAXN],hs[2][MAXN][MAXN],t[MAXN*MAXN]; ull cal(int k,int x,int y,int l) { ull ret=1; for(int i=x;i<=x+l-1;i++) ret=ret*hsn2+hs[k][i][y+l-1]-hs[k][i][y-1]*pre[l]; return ret; } bool check(int x) { int cnt=0; for(int i=1;i<=n-x+1;i++) for(int j=1;j<=n-x+1;j++) t[++cnt]=cal(0,i,j,x); sort(t+1,t+cnt+1); for(int i=1;i<=n-x+1;i++) for(int j=1;j<=n-x+1;j++) { ull cur=cal(1,i,j,x); if(*lower_bound(t+1,t+cnt+1,cur)==cur) return true; } return false; } int main() { scanf("%d",&n); for (int k=0;k<2;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&dat[k][i][j]); for(int k=0;k<2;k++) for(int i=1;i<=n;i++) { hs[k][i][0]=1; for(int j=1;j<=n;j++) hs[k][i][j]=hs[k][i][j-1]*hsn1+dat[k][i][j]; } pre[0]=1;for(int i=1;i<=50;i++) pre[i]=pre[i-1]*hsn1; int l=1,r=n; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) l=mid+1; else r=mid-1; } printf("%d",r); return 0; }