Imbalanced Array(代码源打卡day.1)

做题感想

不得不感慨代码源 d i v . 1 div.1 div.1真的是大佬的世界,第一天每日一题就已经冲到了 c o d e f o r c e s   1900 codeforces\ 1900 codeforces 1900的水平了,不过通过这题学习了一下单调栈的运用我觉得倒也不错。

题意

给出一个数组求出所有子区间最大值和最小值的差值的和。

题解

这里我们将最大值和最小值分开看,所有子区间最大值和最小值差值的和我们也能够认为是所有子区间最大值的和和所有子区间最小值的和的差值,而子区间的最值必定是数组中的某一个数字并且它作为极值的区间必定是连续的。

换句话说我们只要找到了一个值作为极值的区间长度然后通过一系列四则运算就能得出答案了。极值的区间长度可以通过单调栈来维护。

  • 单调栈

    因为之前学过单调队列所以这次学单调栈还是比较容易的,单调队列是两个端点都能进出,单调栈就是只有一个端点能够进出。假设单调栈维护最小值我们只用将当前值与栈顶元素比较大小如果比栈顶元素小,栈顶元素弹出,代表该元素不可能成为接下来的最小值。上述操作结束后剩下的栈顶元素一定比当前元素小,之前的元素都比栈顶元素大,那我们就能够得出当前位置到栈顶元素所在位置前一位,当前元素就是极值。

  • 相等的情况

    因为我们之前还有一种情况就是有一大串元素都相等,这种情况下我们就要固定一个端点,让另一个端点向外延伸。

    换句话说就是当前一个方向允许区间内存在等于的值另一个不存在,不然就会出现重复计算的情况。不理解的同学可以看一下 2   2   2   2 2\ 2\ 2\ 2 2 2 2 2这组数据。

void MAIN(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>num[i];
    for(int i=1;i<=n;i++){//枚举左边界
        while(!st1.empty()&&num[st1.top()]<=num[i]) st1.pop();//maxinum
        while(!st2.empty()&&num[st2.top()]>=num[i]) st2.pop();//mininum
        lmax[i]=st1.empty()?1:st1.top()+1;
        lmin[i]=st2.empty()?1:st2.top()+1;
        st1.push(i);st2.push(i);
    }
    while(!st1.empty()) st1.pop();
    while(!st2.empty()) st2.pop();
    for(int i=n;i>=1;i--){
        while(!st1.empty()&&num[st1.top()]<num[i]) st1.pop();//maxinum
        while(!st2.empty()&&num[st2.top()]>num[i]) st2.pop();//mininum
        rmax[i]=st1.empty()?n:st1.top()-1;
        rmin[i]=st2.empty()?n:st2.top()-1;
        st1.push(i);st2.push(i);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=num[i]*(rmax[i]-i+1)*(i-lmax[i]+1);
        ans-=num[i]*(rmin[i]-i+1)*(i-lmin[i]+1);
    }
    cout<<ans<<endl;
    return ;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值