codevs 2491 玉蟾宮 1159 最大全0子矩陣

玉蟾宮
最大全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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章