1 条题解

  • 0
    @ 2025-8-24 22:21:25

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Alex_Wei
    **

    搬运于2025-08-24 22:21:25,当前版本为作者最后更新于2020-08-23 14:13:26,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题面传送门

    题意简述:给出 nnaia_i,求

    $$\sum_{i=1}^n\sum_{j=i}^n\left(\max_{i\leq k\leq j}a_k-\min_{i\leq k\leq j}a_k\right) $$

    提供一个不一样的思路。


    我们设 fi/gif_i/g_i 为以 ii 结尾的所有子序列的最大 / 最小值之和,那么答案为 figi\sum f_i-g_i

    考虑如何维护 f,gf,g

    不妨设 pi<ip_i<i 为满足 api>aia_{p_i}>a_i 的最大的 pip_i(特别的,如果 pip_i 不存在则为 00),那么有转移方程 fi=fpi+ai×(ipi)f_i=f_{p_i}+a_i\times (i-p_i)pip_i 可以用单调栈维护。

    稍微解释一下上面的转移方程是如何得来的:

    • 因为 aia_ipip_i 以及 pip_i 以前的最大值没有影响(即 [1,pi][1,p_i][1,i][1,i][2,pi][2,p_i][2,i][2,i]\cdots [pi,pi][p_i,p_i][pi,i][p_i,i] 的最大值相同),所以可以直接由 fpif_{p_i} 转移得来。
    • 而根据 pip_i 的定义,后面 ipii-p_i 个子序列(即 [pi+1,i],[pi+2,i],[i,i][p_i+1,i],[p_i+2,i]\cdots,[i,i])的最大值为 aia_i,所以加上 ai×(ipi)a_i\times (i-p_i)
    • 所以转移方程为 fi=fpi+ai×(ipi)f_i=f_{p_i}+a_i\times (i-p_i)

    维护 gg 只需要将 pip_i 的定义中「api>aia_{p_i}>a_i」改为「api<aia_{p_i}<a_i」即可,用两个单调栈即可求出答案。

    时间复杂度 O(n)O(n),常数较小,代码好写,而且跑得飞快,甚至抢到了最优解(2020.8.23)。

    const int N=3e5+5;
    
    ll n,t1,t2,ans,f[N],g[N];
    pii a[N],b[N];
    
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++){
    		ll x=read(),p;
    		while(t1&&x>=a[t1].fi)t1--;
    		while(t2&&x<=b[t2].fi)t2--;
    		p=a[t1].se; f[i]=f[p]+x*(i-p);
    		p=b[t2].se; g[i]=g[p]+x*(i-p);
    		ans+=f[i]-g[i],a[++t1]=b[++t2]={x,i};
    	} cout<<ans<<endl;
    	return 0;
    }
    
    • 1

    信息

    ID
    5530
    时间
    1000ms
    内存
    64MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者