1. 程式人生 > >BZOJ1345:[Baltic2007]序列問題

BZOJ1345:[Baltic2007]序列問題

com www. bzoj ref ble 序列 最小 sla 情況

淺談棧:https://www.cnblogs.com/AKMer/p/10278222.html

題目傳送門:https://lydsy.com/JudgeOnline/problem.php?id=1345

假設當前序列是單調的,那麽顯然答案就是從低往高合並的權值和。

假設\(a\leqslant b \leqslant c\),那麽合並\(a,b\)然後合並\(b,c\)的代價是\(b+c\),顯然要比合並\(b,c\)再合並\(a,c\)的代價\(c+c\)要優。

如果當前序列不單調,那麽必然存在一個位置\(pos\)滿足\(a[pos-1]\geqslant a[pos] \leqslant a[pos+1]\)

。我們只需要把\(a[pos]\)\(a[pos-1],a[pos+1]\)中值較小的那個合並即可。可以證明,能與\(a[pos]\)合並的最小值就是\(min(a[pos-1],a[pos+1])\),如果\(a[pos-1]\)或者\(a[pos+1]\)之前與其它數合並過,並且發生了改變,那麽改變之後的數值顯然是大於\(min(a[pos-1],a[pos+1])\)的。所以我們只需要維護一個單調棧,發現這種情況判斷更新答案即可。最後會剩下一個單調遞減的序列,我們再按照第一種情況處理就行。

時間復雜度:\(O(n)\)

空間復雜度:\(O(n)\)

代碼如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn=1e6+5,inf=2e9+5;

ll ans;
int n,top;
int stk[maxn];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

int main() {
    n=read();
    stk[0]=inf;
    for(int i=1;i<=n;i++) {
        int x=read();
        while(top&&stk[top]<=x)
            ans+=min(stk[top-1],x),top--;
        stk[++top]=x;
    }
    top--;
    while(top)ans+=stk[top],top--;
    printf("%lld\n",ans);
    return 0;
}

BZOJ1345:[Baltic2007]序列問題