懸線法求最大子矩陣
阿新 • • 發佈:2020-09-17
[戳我](https://www.luogu.com.cn/record/38515341)
思路
懸線法,顧名思義,就是我們從一個點開始,想左上方出兩根線,構成一個矩陣,然後遍歷所有的點,取一個最大值就可以了。所以我們之前可以預處理出一個點可以到達的最上面的點和最下面的點,然後列舉寬度,對寬度也就是行上面的點的l和r值取min就可以得到這個矩陣的長和寬了。
程式碼實現
#include<cstdio> #include<algorithm> #include<vector> #include<queue> #include<map> #include<iostream> #include<stack> #include<cstring> #include<cmath> using namespace std; #define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i) #define per(i,n,a) for (int i=n;i>=a;i--) #define MT(x,i) memset(x,i,sizeof(x) ) #define rev(i,start,end) for (int i=start;i<end;i++) #define inf 0x3f3f3f3f #define mp(x,y) make_pair(x,y) #define lowbit(x) (x&-x) #define MOD 1000000007 #define exp 1e-8 #define N 1000005 #define fi first #define se second #define pb push_back typedef long long ll; const ll INF=0x3f3f3f3f3f3f3f3f; typedef vector <int> VI; typedef pair<int ,int> PII; typedef pair<int ,PII> PIII; ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);} ll lcm(ll a,ll b){return a/gcd(a,b)*b;}; void check_max (int &a,int b) { a=max (a,b);} void check_min (int &a,int b) { a=min (a,b);} inline int read() { char ch=getchar(); int x=0, f=1; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } const int maxn=3e3+10; int ans,n,m; int maze[maxn][maxn]; int l[maxn][maxn],r[maxn][maxn]; int up[maxn][maxn]; inline int readc () { char c=getchar (); while (c!='R'&&c!='F') c=getchar (); if (c=='F') return 1; return 0; } int main () { scanf ("%d%d",&n,&m); ans=0; rep (i,1,n) rep (j,1,m) maze[i][j]=readc (),up[i][j]=1,l[i][j]=r[i][j]=j; rep (i,1,n) rep (j,2,m) if (maze[i][j]==1&&maze[i][j-1]==1) l[i][j]=l[i][j-1]; rep (i,1,n) per (j,m-1,1) if (maze[i][j]==1&&maze[i][j+1]==1) r[i][j]=r[i][j+1]; rep (i,1,n) rep (j,1,m) { if (i>1&&maze[i][j]==1&&maze[i-1][j]==1) { check_min (r[i][j],r[i-1][j]); check_max (l[i][j],l[i-1][j]); up[i][j]=up[i-1][j]+1; } check_max (ans,up[i][j]*(r[i][j]-l[i][j]+1)); } printf ("%d\n",3*ans); return 0; }