题意:在一个只有0和1的矩阵里找到一个边长最大的正方形,里面最多只有一个1,求最大的边长。
思路:枚举每个点作为正方形的右下角,预处理出每个点左上角的前缀和,用二分来确定这个点作为右下角时最大的边长,最后所有点的答案取个max即可。
坑点:这题似乎得用读入挂,不然T到爆炸。g++17 t了,g++11和14只需450+ms,不知道为啥。二分边长,再去枚举点会快一点。
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxv = 1010;
int T, n, m, gi[maxv][maxv], A;
void init()
{
A = 0;
}
namespace FastIO {
const int SIZE = 1 << 16;
char buf[SIZE], str[64];
int l = SIZE, r = SIZE;
int read(char *s) {
while (r) {
for (; l < r && buf[l] <= ' '; l++);
if (l < r) break;
l = 0, r = int(fread(buf, 1, SIZE, stdin));
}
int cur = 0;
while (r) {
for (; l < r && buf[l] > ' '; l++) s[cur++] = buf[l];
if (l < r) break;
l = 0, r = int(fread(buf, 1, SIZE, stdin));
}
s[cur] = '\0';
return cur;
}
template<typename type>
bool read(type &x, int len = 0, int cur = 0, bool flag = false) {
if (!(len = read(str))) return false;
if (str[cur] == '-') flag = true, cur++;
for (x = 0; cur < len; cur++) x = x * 10 + str[cur] - '0';
if (flag) x = -x;
return true;
}
template <typename type>
type read(int len = 0, int cur = 0, bool flag = false, type x = 0) {
if (!(len = read(str))) return false;
if (str[cur] == '-') flag = true, cur++;
for (x = 0; cur < len; cur++) x = x * 10 + str[cur] - '0';
return flag ? -x : x;
}
} using FastIO::read;
int check(int x, int y, int a)
{
if (gi[x][y] + gi[x - a][y - a] - gi[x - a][y] - gi[x][y - a] > 1)
return 0;
return 1;
}
int main()
{
read(T);
while (T--)
{
init();
read(n),read(m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
read(gi[i][j]);
gi[i][j] += gi[i][j - 1] + gi[i - 1][j] - gi[i - 1][j - 1];
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int l = 1, r = min(i, j), now = 0;
while (l <= r)
{
int mid = (l + r) / 2;
if (check(i, j, mid))
{
now = mid;
l = mid + 1;
}
else
{
r = mid - 1;
}
}
A = max(A, now);
}
}
printf("%d\n", A);
}
return 0;
}