二分后判定有无两个相同的子正方形,复习了一下二维字符串哈希。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ull unsigned long long
#define inf 1e9
#define eps 1e-10
#define md
#define N 55
#define H 100010
using namespace std;
int n;
ull a[N][N],b[N][N],suma[N][N],sumb[N][N],mi1[N],mi2[N];
const ull cheng1=233333333,cheng2=987654321;
struct ha
{
ull a[H];
bool vis[H];
void clear()
{
memset(vis,0,sizeof(vis));
}
void insert(ull x)
{
int pos=x%H;
while (vis[pos]) { pos++; if (pos>=H) pos-=H; }
vis[pos]=1; a[pos]=x;
}
bool find(ull x)
{
int pos=x%H;
while (vis[pos]&&a[pos]!=x) { pos++; if (pos>=H) pos-=H; }
return vis[pos];
}
} hash;
void buildha()
{
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
suma[i][j]=suma[i][j-1]*cheng1+a[i][j];
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
suma[i][j]=suma[i-1][j]*cheng2+suma[i][j];
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
sumb[i][j]=sumb[i][j-1]*cheng1+b[i][j];
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
sumb[i][j]=sumb[i-1][j]*cheng2+sumb[i][j];
}
mi1[0]=1; for (int i=1;i<=n;i++) mi1[i]=mi1[i-1]*cheng1;
mi2[0]=1; for (int i=1;i<=n;i++) mi2[i]=mi2[i-1]*cheng2;
}
bool ok(int r)
{
hash.clear();
for (int i=r;i<=n;i++)
for (int j=r;j<=n;j++)
hash.insert(suma[i][j]-suma[i][j-r]*mi1[r]-suma[i-r][j]*mi2[r]+suma[i-r][j-r]*mi1[r]*mi2[r]);
for (int i=r;i<=n;i++)
for (int j=r;j<=n;j++)
if (hash.find(sumb[i][j]-sumb[i][j-r]*mi1[r]-sumb[i-r][j]*mi2[r]+sumb[i-r][j-r]*mi1[r]*mi2[r]))
return 1;
return 0;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in","r",stdin); freopen("data.out","w",stdout);
#endif
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%llu",&a[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%llu",&b[i][j]);
buildha();
int l=0,r=n;
while (l!=r)
{
int mid=(l+r+1)>>1;
if (ok(mid)) l=mid; else r=mid-1;
}
printf("%d\n",l);
return 0;
}