LGP2422 [] 良好的感觉 学习笔记
Luogu Link
题意简述
给定一个长为 \(n\) 的序列 \(A\),求 \(\max_{l=1,r=1}^{n,n}\min_{i=l}^{r}A_i\times\sum_{j=l}^{r}A_j\)。
说人话就是框定一个区间,其权值定义为区间最小值乘区间和,最大化此权值并输出它。
做法解析
如果你了解极值分治和笛卡尔树,你会发现这就是经典的极值分治形式,建个笛卡尔树然后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;
}
反思总结
极值分治与笛卡尔树的要素:静态、要考虑所有的区间、权值为区间极值和别的什么东西结合在一起得出。在这题体现的淋漓尽致。