4260. 最大子矩陣 (Standard IO)
阿新 • • 發佈:2020-07-22
首先,我們來一波推論。
假設上圖中 $ABCD$ 和 $EDEF$均滿足題目條件,那麼,
$f_A + f_D \le f_C + f_B$
$f_C + f_F \le f_D + f_E$
兩柿子相加,自然得到: $f_A + f_F \le f_B + f_E$
所以兩個合法的矩陣可以合成一個大的合法矩陣
接著,考慮如何求出最大的矩陣:
先求出所有的合法矩陣,統計每一行中列合法的長度的分段字首和。
接著,我們用單調棧,儲存每個合法矩陣區間的縱座標。為了保證可以拼湊出矩陣,所以遇到長度更短的,立即將前面的矩陣區間進行結算。 當然,最後不要忘了最右邊的剩餘未結算矩陣,放在迴圈外處理。
來個栗子:
對於波峰 $1,2$,遇到更短的$3$,令它們單成一個合法矩陣區間,用矩陣的面積公式結算。最後,我們會留下一個最短的矩陣區間,單獨計算。
#include <bits/stdc++.h> using namespace std; #define N 1010 inline int read(){ int x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } return x * s; } int stac[N], top = 0; // 存座標 int ans = -666; int a[N][N], b[N][N]; int main(){ int n = read(), m = read(); for(int i = 1; i <= n; i++) for(int j = 1;j <= m; j++) a[i][j]= read(), b[i][j] = 1; for(int i = 1;i <= n; i++) for(int j = 1;j <= m; j++) if(a[i][j] + a[i-1][j-1] <= a[i-1][j] + a[i][j-1]) b[i][j] = b[i-1][j] + 1; for(int i = 1;i <= n; i++) for(int j = 1; j <= m; j++) if(b[i][j] == 1) b[i][j] = 0; stac[0] = 1; for(int i = 2;i <= n; in++){ top = 0; for(int j = 2;j <= m; j++){ while(top && b[i][j] <= b[i][stac[top]]){ int temp = b[i][stac[top]] * (j - stac[--top]); ans = max(ans, temp); } stac[++top] = j; } while(top){ ans = max(ans, b[i][stac[top]] * (m - stac[--top] + 1)); } } printf("%d\n", ans); return 0; }