1. 程式人生 > >單調棧詳解 + poj 2796 poj 2559 CF 547B

單調棧詳解 + poj 2796 poj 2559 CF 547B

單調棧:

定義:用棧結構來實現,使得遍歷陣列中棧頂元素保持一定範圍的最大或最小,並且棧中元素始終保持單調性的棧。

功能:用以快速(O(n))求出陣列中某連續子集中的最大值或者最小值。

原理:

以求某連續子集中的最小值為例:

假設某陣列為:

下標 1 2 3 4 5 6
元素 3 1 6 4 5 2

模擬過程:

棧頂下標表示當前元素為從此下標到 上一個棧頂下標的最小值。

1.棧為空,將3的下標壓入棧中。                                                           //當前棧狀態:(棧底 0)1                (棧頂)

2.元素1 <= 3,所以3的下標出棧,1的下標入棧。                             //當前棧狀態:(棧底 0)2                (棧頂)

3.元素1 < 6,6的下標入棧。                                                             //當前棧狀態:(棧底 0) 2  3           (棧頂) 此時表示6為 2 + 1 到 3 的最小值。

4.元素4 <= 6,6的下標出棧,1 < 4,4的下標入棧。                       //當前棧狀態:(棧底0)2 4              (棧頂) 此時表示4為 2 + 1 到 4的最小值。

5.元素4 < 5,5的下標入棧。                                                             //當前棧狀態:(棧底0)2 4 5          (棧頂) 此時表示5為 4 + 1 到 5的最小值。

6.元素2 < 5, 5的下標出棧,2<4,4的下標出棧,2的下標入棧。   //當前棧狀態:(棧底0)2 6              (棧頂) 此時表示2為 2 + 1 到 6的最小值。

7.更新完畢。

整個過程,每出棧一次記錄一次,就可以記錄下整個過程中某個連續子段的最小值,達到了其功能。

以下為例題。

poj 2796:

題意:

1e6的資料向量,求連續的子集的和與子集中最小的數的積的最大值, 並求出這段子集的左右座標。

解析:

不造為啥用stack的stl錯了,用陣列的過了。

這題有兩個注意的點,一個是開始ans置為-1,不然會wa的很慘很慘,因為ans = 0 的時候也更新ansL, ansR。

另一個就是要把-1的節點插入到陣列最後,以便單調棧遍歷完整個陣列。

棧頂為當前的最小值。

程式碼:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

LL a[maxn];
LL sum[maxn];
int s[maxn];

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int n;
    while (~scanf("%d", &n))
    {
        memset(sum, 0, sizeof(sum));
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &a[i]);
            sum[i] += sum[i - 1] + a[i];
        }
        a[++n] = -1;///debug
        LL ans = -1;///debug
        int ansL = -1, ansR = -1;
        int top = 0;
        for (int i = 1; i <= n; i++)
        {
            while (top && a[i] <= a[s[top]])
            {
                LL t = a[s[top]] * (sum[i - 1] - sum[s[top - 1] + 1 - 1]);
                if (ans < t)
                {
                    ans = t;
                    ansL = s[top - 1] + 1;
                    ansR = i - 1;
                }
                top--;
            }
            s[++top] = i;
        }
        printf("%lld\n%d %d\n", ans, ansL, ansR);
    }
    return 0;
}

poj 2559:

題意:

如上圖,給一些寬度為1的矩形的高度,求由矩形圍成的大矩形的最大面積。

資料量1e5。

解析:

找每個範圍中的最小高度,此時這個最小高度作為整個範圍的高,計算面積,掃一遍取最大面積即可。

往前掃一遍,後掃一遍,相當於記錄當前這個點a[i]在哪個區域內始終是最小的。

注意的是後掃的時候,要將棧頂置為-1,否則後掃時棧值無法置為n+1。

比如 5 0 0 0 0 1,這組資料。

程式碼:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

LL a[maxn];
int s[maxn];//stack
int pre[maxn];
int las[maxn];

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int n;
    while (~scanf("%d", &n) && n)
    {
        memset(s, 0, sizeof(s));
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &a[i]);
        }
        int top = 0;
        a[0] = -1;
        for (int i = 1; i <= n; i++)
        {
            while (top && a[i] <= a[s[top]])
            {
                top--;
            }
            pre[i] = s[top];
            s[++top] = i;
        }
        top = 0;
        s[top++] = n + 1;
        a[n + 1] = -1;
        for (int i = n + 1; i >= 1; i--)
        {
            while (top && a[i] <= a[s[top]])
            {
                top--;
            }
            las[i] = s[top];
            s[++top] = i;
        }
        LL ans = 0;
        for (int i = 1; i <= n; i++)
        {
//            cout << pre[i] << " " << las[i] << endl;
            LL t = (las[i] - pre[i] - 1) * a[i];
            if (ans < t)
                ans = t;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

CF 547B:

題目:

Description

Mike is the president of country What-The-Fatherland. There are n bears living in this country besides Mike. All of them are standing in a line and they are numbered from1 ton from left to right.i-th bear is exactlyai feet high.

A group of bears is a non-empty contiguous segment of the line. The size of a group is the number of bears in that group. The strength of a group is the minimum height of the bear in that group.

Mike is a curious to know for each x such that1 ≤ x ≤ n the maximum strength among all groups of sizex.

Input

The first line of input contains integer n (1 ≤ n ≤ 2 × 105), the number of bears.

The second line contains n integers separated by space,a1, a2, ..., an (1 ≤ ai ≤ 109), heights of bears.

Output

Print n integers in one line. For each x from 1 to n, print the maximum strength among all groups of size x.

Sample Input

Input
10
1 2 3 4 5 4 3 2 1 6
Output
6 4 4 3 3 2 2 1 1 1 

題意:

給n個數,找到長度為1 ~ n 的子集中,每個子集中元素的最小值,然後取代表每個子集的最小值的最大值。

解析:

如上題一樣,前後掃一遍,相減出長度。

然後掃一遍就好啦。

感謝這題讓我認識了單調棧!

這題有個要注意的地方:

所有長度掃完之後要做一個下面的更新:

for (int i = n - 1; i >= 1; i--)
{
    maxValue[i] = max(maxValue[i + 1], maxValue[i]);
}
因為有可能一些長度是取不到的,所以醬紫更新一下就行了。

程式碼:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int a[maxn];
int pre[maxn], las[maxn];
int maxValue[maxn];

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
    }
    stack<int> s;
    s.push(0);
    for (int i = 1; i <= n; i++)
    {
        while (!s.empty() && a[i] <= a[s.top()])
            s.pop();
        pre[i] = s.top();
        s.push(i);
    }
    stack<int> t;
    t.push(n + 1);
    for (int i = n; i >= 1; i--)
    {
        while (!t.empty() && a[i] <= a[t.top()])
        {
            t.pop();
        }
        las[i] = t.top();
        t.push(i);
    }
    for (int i = 1; i <= n; i++)
    {
//        cout << pre[i] << " " << las[i] << endl;
        int len = las[i] - pre[i] - 1;
        maxValue[len] = max(maxValue[len], a[i]);
    }
    for (int i = n - 1; i >= 1; i--)
    {
        maxValue[i] = max(maxValue[i + 1], maxValue[i]);
    }
    for (int i = 1; i <= n; i++)
    {
        printf("%d ", maxValue[i]);
    }
    return 0;
}


相關推薦

單調 + poj 2796 poj 2559 CF 547B

單調棧: 定義:用棧結構來實現,使得遍歷陣列中棧頂元素保持一定範圍的最大或最小,並且棧中元素始終保持單調性的棧。 功能:用以快速(O(n))求出陣列中某連續子集中的最大值或者最小值。 原理: 以求某連續子集中的最小值為例: 假設某陣列為: 下標 1 2 3 4 5 6 元

單調單調佇列

單調棧 性質 單調棧是一種特殊的棧,特殊之處在於棧內的元素都保持一個單調性,可能為單調遞增,也可能為單調遞減。 模型 例如下圖就是一個單調遞增的單調棧。 其中的元素從小到大排列。 那麼,如果我們要加入一個新的元素5,5>4,符合要求,就可以直接加入。

JVM 虛擬機器

棧幀 棧幀 (Stack Frame) 是用於支援虛擬機器進行方法呼叫和方法執行的資料結構,它是虛擬機器執行時資料區中的虛擬機器棧 (Virtual  Machine  Stack)的棧元素 。棧幀儲存了方法的區域性變量表、運算元棧、動態連線和方法返回地址等資訊。每一個方能從

雜談——TCP/IP 協議

說到協議棧,我們就先來看看它的定義是什麼。  TCP/IP 協議棧是一系列網路協議的總和,是構成網路通訊的核心骨架,它定義了電子裝置如何連入因特網,以及資料如何在它們之間進行傳輸。 本帥博主之前寫過一篇關於OSI模型的部落格,OSI模型採用

JVM記憶體劃分(堆、)

前言 我們知道,Java的記憶體管理是由JVM虛擬機器來控制的,作為Java程式開發者不需要像C、C++的開發人員一樣對記憶體進行管理,這大大降低了開發的複雜度。但隨之而來的問題是,一旦出現記憶體洩漏和溢位方面的問題,如果不瞭解虛擬機器是如何使用記憶體的,那麼排查錯誤將會變得很困

IPFS協議-身份層

當我們剛安裝好ipfs,第一次使用的時候,我們首先得輸入: ipfs init 這個命令的作用我們之前講過,就是建立一個ipfs節點,我們可以在當前目錄看到一個.ipfs的資料夾,就是節點資料夾。我們可以檢視該資料夾下config檔案,看到節點的id和祕鑰,以及節點的大小等預設屬性。或者也

TCP/IP協議

TCP/IP協議棧 TCP/IP協議是規範不同主機之間進行通訊的一系列協議,其中涉及到資料的封裝,傳輸,定址等一系列內容,是計算機領域非常重要的基礎知識,我們在Java中用到的Socket通訊就是基於TCP/IP協議中的TCP協議,開發為一系列封裝好的API供使用者使用。為什麼要制定這些

(ValueStack)

什麼是值棧 之前web階段,在servlet裡面進行操作,把資料放到域物件裡面,在頁面中使用el表示式獲取到。域物件在一定範圍內,存值和取值。 在struts2裡面提供了本身的一種儲存機制,類似於域物件,是值棧,可以存值和取值。 在action裡面把資料

【虛擬機器】虛擬機器

前言Java 虛擬機器的記憶體模型分為兩部分:一部分是執行緒共享的,包括 Java 堆和方法區;另一部分是執行緒私有的,包括虛擬機器棧和本地方法棧,以及程式計數器這一小部分記憶體。JVM 是基於棧的。但是這個“棧” 具體指的是什麼?難道就是虛擬機器棧?想要回答這個問題我們先要

Struts2的值

          ssh中頁面和action之間資料儲存和傳遞有多種方式,URL傳值,模型驅動,表單傳值,以及我們本文要介紹的值棧等。每種方式都有它的特點和適用範圍,小編根據自身的適用經驗和網上的查

堆和

對堆疊在程式中的作用有更深入的瞭解。不同的語言有不同的函式呼叫規定,這些因素有引數的壓入規則和堆疊的平衡。windows API的呼叫規則和ANSI C的函式呼叫規則是不一樣的,前者由被調函式調整堆疊,後者由呼叫者調整堆疊。兩者通過“__stdcall”和“__cdecl”字首區分。先看下面這段程式碼:

函式呼叫過程中函式

當程序被載入到記憶體時,會被分成很多段 程式碼段:儲存程式文字,指令指標EIP就是指向程式碼段,可讀可執行不可寫,如果發生寫操作則會提示segmentation fault 資料段:儲存初始化的全域性變數和靜態變數,可讀可寫不可執行 BSS:未初始化的全域性變數

HDOJ 3530 Subsequence(單調佇列(含單調佇列))

我們從最簡單的問題開始:給定一個長度為N的整數數列 a [ i ] , i = 0, 1 , . .. , N-1 和區間長度k.要求:      f ( i ) = max { a ( i - k + 1 ) , a ( i - k + 2 ) , . .. , a ( i ) } , i = 0 ,

Android之Fragment回退

前言:本文將結合開發中的實際需求,來講解一下Fragment中的回退棧 對於Activity,當按返回鍵時,能夠返回到上一個Activity,但是,當我們Fragment到Activity中時,如果不做任何處理,當按返回鍵時,當前Fragment都會全部退出,如

POJ 2559 Largest Rectangle in a Histogram(單調

common pst locale str flow bold text function target 【題目鏈接】:click here~~ 【題目大意】: A histogram is a polygon composed of a sequence of

POJ-2559 Largest Rectangle in a Histogram(單調)

comm pict mon include max specified out names align Largest Rectangle in a Histogram Time Limit: 1000MS Memory Limit: 65536K Tota

51nod 1215 數組的寬度&poj 2796 Feel Good(單調

close queue fin click nod stream ++ std tchar   單調棧求每個數在哪些區間是最值的經典操作。   把數一個一個丟進單調棧,彈出的時候[st[top-1]+1,i-1]這段區間就是彈出的數為最值的區間。   poj2796 彈

POJ - 2559 單調

相對 全部 top stl ans clas body 延伸 bre 算是回顧吧 掃描計算時的高度是單調遞減的, 最相對較高的能延伸的矩陣[全部]計算完以後都合並成一個待計算的相對較矮的單一矩陣 規定合並後的矩陣留到下一次計算 一直掃描到棧空(哨兵h[n+1]==0處)即可

題解報告:poj 2559 Largest Rectangle in a Histogram(單調

++i char test case c代碼 ams pac 分享圖片 cas ram Description A histogram is a polygon composed of a sequence of rectangles aligned at a common

10.30 poj 2559 單調

https://blog.csdn.net/zuzhiang/article/details/78135142 http://poj.org/problem?id=2559 my code_1 solution 1 #include<iostream> #include&