翻轉長方形 (不知名oj中一道個人私題)--單調棧維護最大子矩形
阿新 • • 發佈:2019-01-08
怎麼分析這道題呢?
首先 ,我們注意到一點:
不管怎麼操作,任意一個2*2方格中的 "#"個數的奇偶性是不變的。
所以,如果一個2*2方格中有奇數個"#",這個方格里的格子永遠不可能變成同一種顏色。
並且,如果一個矩形中,所有2*2方格中有偶數個"#",那麼它一定可以能變成只有一種顏色的矩形。
為什麼?
先把這個矩形的第一行和第一列都變成同一種顏色,這個操作任何矩形都能做到。
如果這個矩形中,所有2*2方格中有偶數個"#",那麼在左上角的2*2方格一定都是"#"。(一直是偶數個“#”)。這樣在它右邊的2*2方格同樣一定都是"#"。以此類推,它一定可以能變成只有一種顏色的矩形。
然後我們再來維護最大的不包含有奇數個 "#"的2*2方格的矩形。
這是一個經典問題,我們可以用單調棧來解決。
#include<bits/stdc++.h> using namespace std; const int maxn=2005; int h, w, len[maxn], up[maxn], down[maxn], nxt[maxn], ans; char s[maxn][maxn]; int bad(int y, int x){ int ans = (s[y][x] == '#')^ (s[y][x+1] == '#')^ (s[y+1][x] == '#')^ (s[y+1][x+1] == '#'); return ans; } void solve(){ stack<int> stk; for(int i=1;i<=h;i++){ while(!stk.empty() && len[stk.top()] >= len[i]) stk.pop(); if(stk.empty())up[i]=0; else up[i]=stk.top(); if(len[i] != 0)stk.push(i); } while(!stk.empty()) stk.pop(); for(int i=h;i>=1;i--){ while(!stk.empty() && len[stk.top()] >= len[i]) stk.pop(); if(stk.empty())down[i]=h; else down[i]=stk.top(); if(len[i] != 0)stk.push(i); } for(int i=1;i<=h;i++){ ans = max(ans, len[i]*(down[i]-up[i])); // printf("%d:%d %d %d\n",i,len[i],down[i],up[i]); } } int main() { scanf("%d%d",&h,&w); for(int i = 1; i <= h; i++) scanf("%s", s[i]+1); for(int i = 1; i <= w; i++){ for(int j = 1; j <= h; j++){ if(nxt[j]) len[j] = 1; else len[j]++; if(bad(j,i) && i!=w && j!=h) nxt[j] = 1; else nxt[j] = 0; // printf("%d\n",nxt[j]); } // printf("\n"); solve(); } printf("%d\n", ans); return 0; }