LGP2422 [] 良好的感觉 学习笔记

LGP2422 [] 良好的感觉 学习笔记

Luogu Link

题意简述

给定一个长为 n 的序列 A,求 maxl=1,r=1n,nmini=lrAi×j=lrAj

说人话就是框定一个区间,其权值定义为区间最小值乘区间和,最大化此权值并输出它。

做法解析

如果你了解极值分治和笛卡尔树,你会发现这就是经典的极值分治形式,建个笛卡尔树然后dfs一遍就没了。

代码实现

#include <bits/stdc++.h>
using namespace std;
namespace obasic{
    typedef long long lolo;
    template <typename _T>
    void readi(_T &x){
        _T k=1;x=0;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
        x*=k;return;
    }
    template <typename _T>
    void writi(_T x){
        if(x<0)putchar('-'),x=-x;
        if(x>9)writi(x/10);
        putchar(x%10+'0');
    }
    template <typename _T>
    void maxxer(_T &x,_T y){x=max(x,y);}
};
using namespace obasic;
const int MaxN=1e5+5;
int N;lolo A[MaxN],sum[MaxN],ans;
int stk[MaxN],ktp,ls[MaxN],rs[MaxN];
lolo dfs(int u,int l,int r){
    lolo res=1ll*A[u]*(sum[r]-sum[l-1]);
    if(ls[u])maxxer(res,dfs(ls[u],l,u-1));
    if(rs[u])maxxer(res,dfs(rs[u],u+1,r));
    return res;
}
int main(){
    readi(N);
    for(int i=1;i<=N;i++){
        readi(A[i]);
        sum[i]=sum[i-1]+A[i];
    }
    for(int i=1;i<=N;i++){
        int k=ktp;
        while(k&&A[stk[k]]>A[i])k--;
        if(k)rs[stk[k]]=i;
        if(k<ktp)ls[i]=stk[k+1];
        stk[++k]=i,ktp=k;
    }
    ans=dfs(stk[1],1,N);writi(ans);
    return 0;
}

反思总结

极值分治与笛卡尔树的要素:静态、要考虑所有的区间、权值为区间极值和别的什么东西结合在一起得出。在这题体现的淋漓尽致。

posted @   矞龙OrinLoong  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示