玉蟾宮
最大全0子矩陣
曾經做過玉蟾宮,現在拿來再做,卻早就忘了。。。
一直在思考這個東西爲什麼要用單調棧來做。
既然是從左到右掃描,如果上一個矩形的高度大於當前高度,那麼上一個矩形的高度對後面的答案就沒有貢獻了。如果上一個矩形的高度等於當前高度,那我們直接累加得到的答案肯定更優。對於這兩種情況的矩形,既然留之無用,那爲什麼不扔掉!當把所有高度大於等於當前矩形的矩形扔掉後,會發現剩下的就是一個高度單調遞增的矩形集合了。又因爲我們只需要從後面拿,從後面放,所以就可以維護一個單調棧了。
不過,對於需要pop的矩形,雖然多出來的那些高度對後面沒有貢獻了,但是我們可以保留它的寬度對答案的貢獻。即我們一定可以找出一個矩形,它的寬是當前矩形的寬加比當前矩形高的上一個矩形的寬,它的高是當前矩形的高。所以在pop較高矩形的同時,把當前的矩形的寬不斷加上較高矩形的寬度,來對後面的答案做出貢獻。一直到棧頂矩形的高度小於當前矩形的高度,保存當前矩形的寬度爲累計寬度,然後丟進棧中。
那麼對於較高矩形與前面矩形所形成的答案呢?爲了防止遺漏,我們在pop較高矩形的時候,順便統計一下棧頂矩形與前面矩形形成的答案。在寬度逐漸累加的時候,每次pop,都計算一下累計寬度乘以棧頂矩形高度,更新答案。
最後剩下的棧中的單調遞增的矩形,還是按照寬度累加的方法,一直pop,更新答案,直到棧空。
之前對單調棧/單調隊列一直很迷,其實仔細想想豁然開朗
PS:我是看的偉大的DQS學長的博客學的
要是不明白,就手動模擬!!
玉蟾宮:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn=1000+10;
int ans=0,n,m;
int wire[maxn][maxn],wide[maxn];
char ditu[maxn][maxn];
struct lxt
{
int x,y;
};
stack<lxt>s;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
cin>>ditu[i][j];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(ditu[i][j]=='F')
wire[i][j]=wire[i-1][j]+1;
for(int i=1;i<=n;++i)
{
memset(wide,0,sizeof(wide));
for(int j=1;j<=m;++j)
{
lxt f;
int d=0;
while(!s.empty()&&wire[s.top().x][s.top().y]>=wire[i][j])
{
d+=wide[s.top().y];
ans=max(ans,d*wire[s.top().x][s.top().y]);
s.pop();
}
f.x=i;
f.y=j;
s.push(f);
wide[j]=d+1;
}
int d=0;
while(!s.empty())
{
d+=wide[s.top().y];
ans=max(ans,d*wire[s.top().x][s.top().y]);
s.pop();
}
}
ans*=3;
printf("%d",ans);
return 0;
}
最大全0子矩陣:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn=2000+10;
int n,ans;
int h[maxn][maxn],wide[maxn];
struct lxt
{
int x,y;
};
stack<lxt>s;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
int x;
scanf("%d",&x);
if(!x) h[i][j]=h[i-1][j]+1;
}
for(int i=1;i<=n;++i)
{
memset(wide,0,sizeof(wide));
for(int j=1;j<=n;++j)
{
int d=0;
while(!s.empty()&&h[s.top().x][s.top().y]>=h[i][j])
{
d+=wide[s.top().y];
ans=max(ans,d*h[s.top().x][s.top().y]);
s.pop();
}
s.push((lxt){i,j});
wide[j]=++d;
}
int d=0;
while(!s.empty())
{
d+=wide[s.top().y];
ans=max(ans,d*h[s.top().x][s.top().y]);
s.pop();
}
}
printf("%d",ans);
return 0;
}