本题使用悬线法。
针对于每一点来说,他向上能到多长取决于上一个点的情况,如果上一个点与他相反那就h[i][j] = h[i-1][j]+1,否则的话就是 1。
那么对于每一个点左边最长是多少,右边最长是多少都能求出来。
然后我们可以看到在竖直方向会产生许多悬线,那么接下来去取这些悬线最大到左边和右边分别是多少。
最后的结果就是某个悬线可以形成的最大矩形,再根据面积公式计算即可。
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 2000+10; int n, m; int mp[maxn][maxn]; int h[maxn][maxn], l[maxn][maxn], r[maxn][maxn]; signed main() { cin>>n>>m; for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { cin>>mp[i][j]; } } //先向上计算向上可到达的最长长度。 for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { if (mp[i][j]==mp[i-1][j]||i==1) h[i][j] = 1; else h[i][j] = h[i-1][j] + 1; if (mp[i][j]==mp[i][j-1]||j==1) l[i][j] = 1; else l[i][j] = l[i][j-1] + 1; } // for (int i=1;i<=n;i++) // { // for (int j=1;j<=m;j++) // { // cout<<h[i][j]<<' '; // } // cout<<'\n'; // } //倒着遍历取找最右边 for (int i=1;i<=n;i++) for (int j=m;j>=1;j--) { if (j==m||mp[i][j]==mp[i][j+1]) r[i][j] = 1; else r[i][j] = r[i][j+1]+1; } // for (int i=1;i<=n;i++) // { // for (int j=1;j<=m;j++) // { // cout<<r[i][j]<<' '; // } // cout<<'\n'; // } //走一遍求每一个悬线的左右两边最大距离 for (int i=2;i<=n;i++) for (int j=1;j<=m;j++) { if (h[i][j]>1) { l[i][j] = min(l[i][j], l[i-1][j]); r[i][j] = min(r[i][j], r[i-1][j]); } } // for (int i=1;i<=n;i++) // { // for (int j=1;j<=m;j++) // { // cout<<l[i][j]<<' '; // } // cout<<'\n'; // } int square=0, rectangle=0; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { square = max(square, h[i][j]*(l[i][j]+r[i][j]-1)); int len = min(h[i][j], l[i][j]+r[i][j]-1); rectangle = max(rectangle, len*len); } cout<<rectangle<<endl; cout<<square; return 0; }