题目链接

https://ac.nowcoder.com/acm/contest/7604/D

解题思路

参考
先看看大佬的大致思路,再看我的代码讲解。

代码讲解

先扫一眼代码,再看讲解。

构建最大值/最小值区间:

大佬写的代码比较难理解,但是时间复杂度应该比这样低点。
抽丝剥茧,分离出本质,就是找第i个位置之后第一个比a[i]大的位置,将其保存在ka[i]中。
所以说,区间[i,ka[i]-1]的最大值为a[i]。
同理,找到第i个位置之后第一个比a[i]小的位置,将其保存在ki[i]中。区间[i,ki[i]-1]的最小值为a[i]。

接下来的循环

ans[i]表示区间长度为i的最终和与区间长度为i-1的最终和之差。
枚举起点位置,找到最大值最小值都不变的一段区间,让ans[L]+=最大值最小值,ans[R+1]-=最大值最小值。
每一段区间的更新,右端点都是用最大值右端点和最小值右端点最小的去更新。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
int a[N],ki[N],ka[N],ans[N];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];

    //构建最大值区间
    for(int i=n;i>=1;i--) {
        int j=i+1;
        for(;j<=n;j++) 
            if(a[j]>a[i]) {ka[i]=j;break;}
        if(j==n+1) ka[i]=n+1;
    }
    //构建最小值区间
    for(int i=n;i>=1;i--) {
        int j=i+1;
        for(;j<=n;j++) 
            if(a[j]<a[i]) {ki[i]=j;break;}
        if(j==n+1) ki[i]=n+1;
    }

    for(int i=1;i<=n;i++) {
        int ma=i;//区间最大值的位置 
        int mi=i;//区间最小值的位置 
        int minL=i;//最小值区间的左端点
        int minR=ki[minL]-1;//最小值区间的右端点
        int maxL=i;//最大值区间的左端点
        int maxR=ka[maxL]-1;//最大值区间的右端点 
        while(1) {
            int L=minL-i+1,R=min(minR,maxR)-i+1;
            //差分数组赋值 
            ans[L]  +=a[mi]*a[ma];
            ans[R+1]-=a[mi]*a[ma];
            //刷新最大值区间左端点和最小值区间左端点 
            minL=maxL=min(minR,maxR)+1;
            if(minL>=n+1) break;
            //刷新最大值区间右端点和最小值区间右端点 
            if(minL>minR) mi=minL,minR=ki[minL]-1;
            if(maxL>maxR) ma=maxL,maxR=ka[maxL]-1;
        }
    }
    for (int i=1;i<=n;i++) ans[i]+=ans[i-1];//差分求和
    for (int i=1;i<=n;i++) cout<<ans[i]<<' ';

}

吐槽

太难了吧