题目
思路
本题作为一道提高+/省选-的题,基本思路是自己想出来的,拿了90,然后有一个小bug一直没发现,拿来标程对比,改了这个bug然后AC,还是很开心的。
首先,借鉴最大正方形的经验,这种题应该下手画图,不出意外,通过画图找到了状态转移的规律。
首先我们将d(i,j)定义为,(i,j)为一个对角线的右下角或左下角时,最长的对角线代表正方形内无其它1的对角线长度。
这里我们先拿右下角分析。
我们定义lf[i][j],元素(i,j)的左边第一个1的横坐标,uf[i][j],元素(i,j)上边第一个1的纵坐标。由图可知,设对角线左上角坐标为(a,b),d[i][j] = d[i-1][j-1]+1当且仅当uf[i][j] < a && lf[i][j] < b。而此处对角线左上角的坐标,可以根据d[i-1][j-1]的值来确定。这就明确了状态转移的条件。
拿左下角分析时,有两种方法,要么直接将图像左右反转,然后再用一遍之前的代码,要么再根据uf和lf制定另一个状态转移条件判断。第一种是偷懒的办法。。我之前试了。。洛谷最后一个点会TLE,第二种用uf和lf套来套去,在此处就不说了。
确定对角线另一端的坐标。
可以根据tl=d[i-1][j-1]或d[i-1][j+1],而l
∈
∈
[1,tl],将l从大到小遍历,每次的另一端坐标就是d[i-l][j-l]或d[i-l][j+l]。
注意此处不能直接用tl而不用l遍历小于等于tl的每一个值,本题只有一个数据点能反映这个事实,这也是我得90的bug,考虑如下情况:
0 0 0 0 0 0 0
1 1 0 0 1 0 0
0 0 1 0 0 0 0
0 0 0 1 0 0 0
1 0 0 0 1 0 0
0 1 0 0 0 1 0
1 0 0 0 0 0 1
显然在考虑加粗体1时,如果直接用tl=4,直接就否定了这个点作为右小角端点的权利。而l=3时,这个点可以,从而在整个图形中得到了长度为5的合法对角线。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 2500 + 10;
int n, m, G[maxn][maxn], d[maxn][maxn], lf[maxn][maxn], uf[maxn][maxn];
int main() {
scanf("%d%d", &n, &m);
_rep(i, 1, n) _rep(j, 1, m) scanf("%d", &G[i][j]);
// 打表lf和uf
int last;
_rep(i, 1, n) {
last = 0;
_rep(j, 1, m)
if (G[i][j] == 1) {
lf[i][j] = last;
last = j;
}
else {
lf[i][j] = last;
}
}
_rep(j, 1, m) {
last = 0;
_rep(i, 1, n)
if (G[i][j] == 1) {
uf[i][j] = last;
last = i;
}
else {
uf[i][j] = last;
}
}
int ans = 0;
// (i,j)作为一个对角线的右下角时
_rep(i,1,n)
_rep(j, 1, m)
if (G[i][j] == 1) {
d[i][j] = 1;
int tl = d[i - 1][j - 1];
for (int l = tl; l >= 1; l--) {
if (uf[i][j] < i - l && lf[i][j] < j - l) {
d[i][j] = l + 1;
break;
}
}
ans = max(ans, d[i][j]);
}
//(i,j)作为一个对角线的左下角时
_rep(i, 1, n)
for(int j = m; j>=1; j--)
if (G[i][j] == 1) {
d[i][j] = 1;
int tl = d[i - 1][j + 1];
for (int l = tl; l >= 1; l--) {
if (uf[i][j + l] == i - l && lf[i][j + l] == j && uf[i][j] < i - l && lf[i - l][j + l] < j) {
d[i][j] = l + 1;
break;
}
}
ans = max(ans, d[i][j]);
}
printf("%d\n", ans);
return 0;
}