样例过了,我是枚举右下角的点,向上边和左边拓展
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int n, m;
unsigned long long a[1010][1010], b[1010][1010], c[1010][1010];
unsigned long long f[1010], f2[1010];
bool check(int x, int y, int len)
{
if(x-len<0||y-len<0)
return 0;
int res1=a[x][y]-a[x-len][y]*f[len]-a[x][y-len]*f2[len]+a[x-len][y-len]*f[len]*f2[len];
int yy=m-(y-len);
int res2=b[x][yy]-b[x-len][yy]*f[len]-b[x][yy-len]*f2[len]+b[x-len][yy-len]*f[len]*f2[len];
int xx=n-(x-len);
int res3=c[xx][y]-c[xx-len][y]*f[len]-c[xx][y-len]*f2[len]+c[xx-len][y-len]*f[len]*f2[len];
if(res1==res2&&res2==res3)
return 1;
else
return 0;
}
void hs()
{
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
a[i][j]=a[i][j-1]*13331ull+a[i][j];
b[i][j]=b[i][j-1]*13331ull+b[i][j];
c[i][j]=c[i][j-1]*13331ull+c[i][j];
}
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
a[i][j]+=a[i-1][j]*13331ull;
b[i][j]+=b[i-1][j]*13331ull;
c[i][j]+=c[i-1][j]*13331ull;
}
f[0]=1ull;
for(int i=1; i<=n; i++)
f[i]=f[i-1]*13331ull;
f2[0]=1ull;
for(int i=1; i<=m; i++)
f2[i]=f2[i-1]*13331ull;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
scanf("%d", &a[i][j]);
b[i][m-j+1]=a[i][j];
c[n-i+1][j]=a[i][j];
}
hs();
int ans=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
int l=0, r=min(n, m), maxx=1;
while(l<=r)
{
int mid=l+r>>1;
if(check(i, j, mid))
maxx=max(maxx, mid+1), l=mid+1;
else
r=mid-1;
}
ans+=(maxx+1)/2;
}
printf("%d", ans);
return 0;
}
/*
5 5
4 2 4 4 4
3 1 4 4 3
3 5 3 3 3
3 1 5 3 3
4 2 1 2 4
*/