1. 程式人生 > >洛谷——P2659 美麗的序列

洛谷——P2659 美麗的序列

貢獻 ble http ffffff oid uil amp () cst

P2659 美麗的序列

單調棧維護區間最小值,單調遞增棧維護區間最小值,

考慮當前數對答案的貢獻,不斷加入數,如果加入的數$>$棧頂,說明棧頂的元素對當前數所在區間是有貢獻的,同時加入當前的數。

反之,若當前加入的數比棧頂元素小,那麽棧頂元素(所謂的最小值)已經失去了價值,因為他不會再對後面的區間造成影響,所以彈出棧頂,同時更新$ans$

#include<iostream>
#include<cstdio>
#include<algorithm>

#define N 10000000
#define inf 0x7fffffff
#define
LL long long using namespace std; LL ans,top; struct node{ int val,pos; }S[N]; int n; int main() { scanf("%d",&n); for(int x,i=1;i<=n;i++){ scanf("%d",&x); if(!top) S[++top].val=x,S[top].pos=i; else{ while(S[top].val>x) {ans=max(ans,1ll*(i-S[top-1
].pos-1)*S[top].val);--top;} S[++top].pos=i,S[top].val=x; } } for(int i=1;i<=top;i++) ans=max(ans,1ll*(n-S[i-1].pos)*S[i].val); printf("%lld",ans); return 0; }

線段樹查詢區間最小值,找到區間最小值的位置,不斷遞歸尋找最小值。

一段區間的價值即為$(r-l+1)*minn$

這種做法竟然沒有$TLE$,神奇,難道就是因為他不斷遞歸找了最小值的位置嗎?

#include<iostream>
#include<cstdio>
#include<algorithm>

#define N 10000000
#define inf 0x7fffffff
using namespace std;

struct nodE{
    int l,r,w_max,pos;
}tr[N];

int n;
long long ans;

void push_up(int k){
    if(tr[k<<1].w_max<tr[k<<1|1].w_max) tr[k].pos=tr[k<<1].pos;
    else tr[k].pos=tr[k<<1|1].pos;
    tr[k].w_max=min(tr[k<<1].w_max,tr[k<<1|1].w_max);
}

void build(int k,int l,int r){
    tr[k].l=l,tr[k].r=r;
    if(l==r) {scanf("%d",&tr[k].w_max);tr[k].pos=l;return;}
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push_up(k);
}

nodE query(int k,int ql,int qr){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=ql&&r<=qr) return tr[k];
    nodE x,y;x.w_max=y.w_max=inf;
    if(ql<=mid) x=query(k<<1,ql,qr);
    if(qr>mid) y=query(k<<1|1,ql,qr);
    return x.w_max>y.w_max ? y :x;
}

void slove(int l,int r){
    nodE px=query(1,l,r);
    ans=max(ans,1ll*(r-l+1)*px.w_max);
    if(l<px.pos) slove(l,px.pos-1);
    if(r>px.pos) slove(px.pos+1,r);
}

int main()
{
    scanf("%d",&n);
    build(1,1,n);
    slove(1,n);
    printf("%lld",ans);
    
    return 0;
}

洛谷——P2659 美麗的序列