BZOJ1567 [JSOI2008]Blue Mary的战役地图(二分+二维hash)
题意
问边长为n的两个正方形中最大的相等子正方形。(n<=50)
题解
用到了二维hash,感觉和一维的不太一样。
对于列行有两个不同的进制数然后也是通过类似前缀和的方法差分出一个矩形的hash值
这样可以0(1)的算出一个正方形的hash值。
然后我们二分长度x,每一次遍历整个长度为x的子正方形n2判断即可。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<map> 7 using namespace std; 8 const int mod1=38833; 9 const int mod2=29123; 10 map<unsigned,int> ma; 11 unsigned long long pow1[60],pow2[60],hash1[60][60],hash2[60][60]; 12 int n,ans,t; 13 bool judge(int x){ 14 ++t; 15 for(int i=x;i<=n;i++) 16 for(int j=x;j<=n;j++){ 17 ma[hash1[i][j]-hash1[i-x][j]*pow2[x]-hash1[i][j-x]*pow1[x]+hash1[i-x][j-x]*pow1[x]*pow2[x]]=t; 18 } 19 for(int i=x;i<=n;i++) 20 for(int j=x;j<=n;j++){ 21 if(ma[hash2[i][j]-hash2[i-x][j]*pow2[x]-hash2[i][j-x]*pow1[x]+hash2[i-x][j-x]*pow1[x]*pow2[x]]==t)return true; 22 } 23 return false; 24 } 25 int main(){ 26 scanf("%d",&n); 27 pow1[0]=pow2[0]=1; 28 for(int i=1;i<=n;i++){ 29 pow1[i]=pow1[i-1]*mod1; 30 pow2[i]=pow2[i-1]*mod2; 31 } 32 for(int i=1;i<=n;i++) 33 for(int j=1;j<=n;j++){ 34 int a; 35 scanf("%d",&a); 36 hash1[i][j]=hash1[i][j-1]*mod1+a; 37 } 38 for(int i=1;i<=n;i++) 39 for(int j=1;j<=n;j++){ 40 int a; 41 scanf("%d",&a); 42 hash2[i][j]=hash2[i][j-1]*mod1+a; 43 } 44 for(int i=1;i<=n;i++) 45 for(int j=1;j<=n;j++) 46 hash1[i][j]=hash1[i-1][j]*mod2+hash1[i][j]; 47 for(int i=1;i<=n;i++) 48 for(int j=1;j<=n;j++) 49 hash2[i][j]=hash2[i-1][j]*mod2+hash2[i][j]; 50 int l=1;int r=n; 51 while(l<=r){ 52 int mid=(l+r)>>1; 53 if(judge(mid)){ 54 l=mid+1; 55 ans=mid; 56 } 57 else r=mid-1; 58 } 59 printf("%d",ans); 60 return 0; 61 }