原题链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1424
逐渐找到做这种题的感觉了。
二分法。g[i][j]存储坐标(i, j)的值,s[i][j]存储的值为左上角为起始点(1,1),右下角为(i, j)的矩形区域内所有值的和,那么:
s[i][j] = g[i][j] + s[i-1][j] + s[i][j-1] - s[i-1][j-1]
扫描整个矩形,遇到为“1”的点就将其作为起点,开始二分边长,利用数组s在O(1)的时间复杂度内判断是否满足为由1组成的正方形,不管更新最大值即可。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 1005 int g[N][N], s[N][N]; int n, m; bool ok(int i, int j, int mid) { int t1 = mid * mid; int t2 = s[i+mid-1][j+mid-1] - s[i+mid-1][j-1] - s[i-1][j+mid-1] + s[i-1][j-1]; return t1 == t2; } int bs(int i, int j) { int l = 1, r = N; while(l < r) { int mid = (l + r) >> 1; if(i + mid - 1 > m || j + mid - 1 > n) r = mid; else if(ok(i, j, mid)) l = mid+1; else r = mid; } return (l-1) * (l-1); } int main() { int ans; while(scanf("%d%d", &n, &m) != EOF) { for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) scanf("%d", &g[i][j]); for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) s[i][j] = g[i][j] + s[i-1][j] + s[i][j-1] - s[i-1][j-1]; ans = 0; for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) if(g[i][j]) ans = max(ans, bs(i, j)); printf("%d ", ans); } return 0; }