先处理出每个位置,前后左右四个方向的连续的1的个数。。由于正方形的对角顶点一定在对角线上,所以直接暴力枚举。
#include <cstdio>
#include <cstring>
const int maxn = 1005;
int l[maxn][maxn];
int r[maxn][maxn];
int u[maxn][maxn];
int d[maxn][maxn];
int a[maxn][maxn];
int n;
void init(){
memset(l, 0, sizeof(l));
memset(r, 0, sizeof(r));
memset(u, 0, sizeof(u));
memset(d, 0, sizeof(d));
}
void work(){
//left and up
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
if(a[i][j]==0){
l[i][j] = 0;
u[i][j] = 0;
}
else{
l[i][j] = l[i][j - 1] + 1;
u[i][j] = u[i - 1][j] + 1;
}
}
}
//right and down
for(int i = n; i >= 1; i --){
for(int j = n; j >= 1; j --){
if(a[i][j]==0){
r[i][j] = 0;
d[i][j] = 0;
}
else{
r[i][j] = r[i][j + 1] + 1;
d[i][j] = d[i + 1][j] + 1;
}
}
}
}
struct Node{
int x ;
int L,R;
}point[maxn];
int min(int x, int y){
if(x < y)
return x;
return y;
}
int findans(int x, int y){
int ret = 0 ;
int s = 0;
int m = 0;
for(int i = x, j= y ; i <= n && j <= n; i ++, j ++){
++ s;
point[m].x = s;
point[m].R = s + min(r[i][j], d[i][j]) - 1;
point[m].L = s - min(l[i][j], u[i][j]) + 1;
++ m;
}
for(int i = 0; i < m; i ++){
for(int j = i + 1; j < m; j ++){
if(point[i].R >= point[j].x && point[j].L <= point[i].x){
++ ret;
}
}
}
return ret;
}
int solve(){
//枚举所有斜线的起点
int ans = 0;
for(int i = 1; i < n; i++)
ans += findans(i, 1);
for(int j = 2; j < n; j++)
ans += findans(1, j);
return ans;
}
int main(){
int t;
int cas = 1;
// freopen("test.in", "r", stdin);
scanf("%d", &t) ;
while(t--){
scanf("%d", &n);
init();
int ans = 0;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
scanf("%d", &a[i][j]);
if(a[i][j]==1)
ans ++;
}
}
//处理出l,r,u,d四个数组的值
work();
//得到答案
printf("Case %d: %d\n", cas++, ans + solve());
}
return 0 ;
}