# 二维Hash的求法：

void init() {
//一行的哈希值
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
a[i][j] = a[i][j - 1] * B1 + _a[i][j];
//一列的哈希值
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
a[i][j] += a[i - 1][j] * B2;
}
//查询
unsigned long long query(int x, int y, int X, int Y) {
unsigned long long res = a[x][y] - a[X][Y - 1] * pow1[y - Y + 1] - a[X - 1][Y] * pow2[x - X + 1] + a[X - 1][Y - 1] * pow1[y - Y + 1] * pow2[x - X + 1];
return res;
}

# AC代码：

#include <cstdio>
#include <iostream>

#define RI register int
#define mid (l + r >> 1)

using namespace std;

template <class T>
x = 0; T f = 1; char c = getchar();
while(c > '9' || c < '0') {
if(c == '-')
f = -f;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
x *= f;
}

typedef unsigned long long ull;
const int N = 1e3 + 1;
const int B1 = 233;
const int B2 = 332;
int n, m, ans;
ull a[N][N], b[N][N], c[N][N];
ull pow1[N], pow2[N];

for(RI i = 1; i <= n; i++)
for(RI j = 1; j <= m; j++)
b[i][m - j + 1] = a[i][j],//左右翻转
c[n - i + 1][j] = a[i][j];//上下翻转
}
//二维哈希预处理
inline void init() {
for(RI i = 1; i <= n; i++)
for(RI j = 1; j <= m; j++)
a[i][j] += a[i][j - 1] * B1,
b[i][j] += b[i][j - 1] * B1,
c[i][j] += c[i][j - 1] * B1;
for(RI i = 1; i <= n; i++)
for(RI j = 1; j <= m; j++)
a[i][j] += a[i - 1][j] * B2,
b[i][j] += b[i - 1][j] * B2,
c[i][j] += c[i - 1][j] * B2;
pow1[0] = pow2[0] = 1;
for(RI i = 1, tmp = max(n, m); i <= tmp; i++)
pow1[i] = pow1[i - 1] * B1,
pow2[i] = pow2[i - 1] * B2;
}
//判断三个矩阵是否相同
inline bool check(int x, int y, int le) {
//因为会自然溢出的缘故，unsigned 没有小于0的时候 所以不能写x-le<0 （细节
if(x > n || y > m || x < le || y < le)
return false;
ull res1 = a[x][y] - a[x][y - le] * pow1[le] - a[x - le][y] * pow2[le] + a[x - le][y - le] * pow1[le] * pow2[le];
int tmp = y;
y = m - (y - le);//位置要调整（细节
ull    res2 = b[x][y] - b[x][y - le] * pow1[le] - b[x - le][y] * pow2[le] + b[x - le][y - le] * pow1[le] * pow2[le];
y = tmp, x = n - (x - le);//位置要调整（细节
ull res3 = c[x][y] - c[x][y - le] * pow1[le] - c[x - le][y] * pow2[le] + c[x - le][y - le] * pow1[le] * pow2[le];
return res1 == res2 && res2 == res3;
}
inline void solve() {
int tmp = min(n, m);
//这里要分两点讨论，边长为偶数的是枚举格点，而边长为奇数的则是枚举格子（细节
for(RI i = 0; i < n; i++)
for(RI j = 0; j < m; j++) {
int l = 1, r = tmp, res = 0;
while(l < r) {
if(check(i + mid, j + mid, mid + mid))
res = mid, l = mid + 1;
else
r = mid;
}
ans += res;
}
for(RI i = 0; i < n; i++)
for(RI j = 0; j < m; j++) {
int l = 1, r = tmp, res = 0;
while(l < r) {
if(check(i + mid, j + mid, mid + mid + 1))
res = mid, l = mid + 1;
else
r = mid;
}
ans += res;
}
ans += n * m;    //1格的也算对称正方形，不要漏了（细节
printf("%d\n", ans);
}

int main() {
}