当前位置: 首页 > article >正文

算法日记10:SC62求和(单调栈)(共享求解)

一、题目

在这里插入图片描述

二、题解:

1、首先,我们看到题目的第一个想法,就是把样例答案如何求解给列出来,图例如下

在这里插入图片描述

2、通过分析样例,可以很清晰的发现每一个数字都有其管辖的区间,因此我们可以想到能否找到一个数字它所管辖区间的左端点和右端点

在这里插入图片描述

3、以5来举例,可以发现它一共管辖了 3 ∗ 3 3*3 33个区间,所以它对答案的贡献 9 ∗ 5 = 45 9*5=45 95=45

在这里插入图片描述

  • 3.1:因此,我们可以简单算出样例答案
    在这里插入图片描述

4、但是,会出现一种出现重复数字的情况

  • 比如,在下面这个样例中:就会出现管辖区间分配的特殊情况
    在这里插入图片描述
  • 这时,我们就需要规定一个明确的规则,(也就是规定好给谁,这里以左闭右开为例),也就是说我们规定,如果一个区间有重复元素,那么我们就把这个区间给靠右的元素,但是这个用代码如何实现呢?
    在这里插入图片描述

5、我们可以用单调栈的思想的解决,找到左边第一个<=a[i]的值(因为等于也归它管,但是<就不归它管了),//找到右边第一个<a[i]的值(因为<=都不归它管)

//找到左边第一个<=a[i]的值
    ll top=0;
    for(int i=1;i<=n;i++)
    {
        while(top&&a[stk[top]]>a[i]) //栈不为空/栈顶元素>a[i]
        {
            top--;  //栈顶元素出栈
        }
        if(top==0) l[i]=0; //表示左边没有<=的数
        else l[i]=stk[top];

        stk[++top]=i;   //入栈
    }

    //找到右边第一个<a[i]的值
    top=0;
    for(int i=n;i>=1;i--)
    {
        while(top&&a[stk[top]]>=a[i]) //栈不为空/栈顶元素>=a[i]
        {
            top--;  //栈顶元素出栈
        }
        if(top==0) r[i]=n+1; //表示右边边没有<=的数
        else r[i]=stk[top];

        stk[++top]=i;   //入栈
    }

6、区间求解原理(数学原理)

  • 在最后一步,我们使用sum+=a[i]*(i-l[i])*(r[i]-i)来求解,其实这非常好证明,如下:
    在这里插入图片描述
  • 以2举例,我们可以清晰看到证明过程
  • 这个点的贡献= a [ i ] ∗ ( i − l ) ∗ ( r − i ) a[i]*(i-l)*(r-i) a[i](il)(ri)
a[i]-->这个点的值
l-->左边第一个>a[i]的下标值
r-->右边第一个>=a[i]的下标值

三、完整代码如下

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 2e5 + 7;
ll a[N];
ll stk[N];
ll l[N], r[N]; //模拟单调栈,存储下标

void solve()
{
    int n; cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    //找到左边第一个<=a[i]的值
    ll top=0;
    for(int i=1;i<=n;i++)
    {
        while(top&&a[stk[top]]>a[i]) //栈不为空/栈顶元素>a[i]
        {
            top--;  //栈顶元素出栈
        }
        if(top==0) l[i]=0; //表示左边没有<=的数
        else l[i]=stk[top];

        stk[++top]=i;   //入栈
    }

    //找到右边第一个<a[i]的值
    top=0;
    for(int i=n;i>=1;i--)
    {
        while(top&&a[stk[top]]>=a[i]) //栈不为空/栈顶元素>=a[i]
        {
            top--;  //栈顶元素出栈
        }
        if(top==0) r[i]=n+1; //表示右边边没有<=的数
        else r[i]=stk[top];

        stk[++top]=i;   //入栈
    }
    
    ll sum=0;
    for(int i=1;i<=n;i++)   //遍历相乘
    {
        sum+=a[i]*(i-l[i])*(r[i]-i);
    }
    cout<<sum<<'\n';
}


int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1; //cin >> _;
    while (_--) solve();
    system("pause");

    return 0;
}

http://www.kler.cn/a/532213.html

相关文章:

  • PHP XML操作指南
  • 使用Visual Studio打包Python项目
  • 2025/2/3 云服务器数据库与idea相连
  • Hive:窗口函数(1)
  • 深度学习-98-大语言模型LLM之基于langchain的代理create_react_agent工具
  • 在CentOS服务器上部署DeepSeek R1
  • 冷链监控系统
  • 4 前置技术(下):git使用
  • ElasticStack简介及应用
  • 基于开源AI智能名片2 + 1链动模式S2B2C商城小程序视角下的个人IP人设构建研究
  • arkui-x stack叠层解决焦点变换带来的布局问题
  • 《海丰县蔡氏简介》--汕尾市海陆丰大宗蔡姓源流简介
  • 见证中国力量|暴雨服务器全面支持DeepSeek
  • 交叉验证、精确率、召回率
  • 【阅读笔记】LED显示屏非均匀度校正
  • Vue.js 使用组件库构建 UI
  • 北京怀柔区区划地图矢量cdr格式ai高清大图
  • 一次线程数超限导致的hive写入hbase作业失败分析
  • 2.8学习记录
  • 什么是物理地址,什么是虚拟地址?
  • H. The Third Letter
  • 接入DeepSeek大模型
  • 蓝桥杯思维训练营(三)
  • 【Leetcode刷题记录】2090. 半径为 k 的子数组平均值--定长滑动窗口解法和前缀和解法
  • 基于RK3588+算能BM1684X的云电脑/云手机系统设计与实现
  • 【Go语言圣经】第七节:接口