蓝桥杯刷题018——和与乘积(贪心)

news2025/2/25 10:26:02

2021国赛:和与乘积

题目描述

给定一个数列 A=(a_1,a2,\cdot \cdot \cdot ,an),问有多少个区间[L,R] 满足区间内元素的乘积等于他们的和,即a_L\cdot a_{L+1}\cdot \cdot \cdot \cdot a_{R}=a_L+a_{L+1}+\cdot \cdot \cdot +a_R

输入描述

输入第一行包含一个整数 n,表示数列的长度。

第二行包含 n 个整数,依次表示数列中的数 a1​,a2​,⋯,an​。

输出描述

输出仅一行,包含一个整数表示满足如上条件的区间的个数。

输入输出样例

输入

4
1 3 2 2

输出

6

样例解释

符合条件的区间为 [1,1],[1,3],[2,2],[3,3],[3,4],[4,4]。

评测用例规模与约定

对于 20% 的评测用例,n≤3000;

对于 50% 的评测用例,n≤20000;

对于所有评测用例,1≤n≤200000,1≤ai​≤200000

题目大意

给定一个数列,求有多少个子区间,它们的区间和与区间积相等。

1、简单做法:暴力法

构造前缀和以及前缀积的数组,来进行判断
暴力法的局限:乘积过大,寻找区间超时

2、贪心法

观察数据范围

对于所有评测用例,1≤ n ≤200000,1 ≤ai ≤200000。
所有元素之和最大只能到4*10^10
log_2(4 * 10^{10})=35.2193
36个2相乘就会超过4*10^10,如果有数比2大,乘积只会更大。
因此,满足和与积相等的区间,非1的数字一定不会超过35个。
数字1的特性:
可以在不改变区间积的条件下改变区间和

解题思路

  1. 选出序列中不为1的数每次选取最多不超过35个,计算这些数的区间和区间积
  2. 如果区间积>区间和,计算当前区间左右两边的1的个数,判断能否通过补l的方式来使得区间和=区间积
  3. 通过计算补1的个数,就可以计算出使得当前和=积的区间个数,累计入总结果
  4. 对所有不为1的数全部判断完后,最终累计的总结果即为答案

下面对第一、三步进行详细说明: 

 1、选出序列中不为l的数,每次选取最多不超过3个,计算这些数的区间和与区间积

index:—个队列deque(),记录每个非1的数的下标,算完一个就把它从队列移出。

S:前缀和数组
选数方式:

  • 取出当前index队列头,以它为基准,不断往后判断,直到第35个数为止(队列不足35个数就到最后一个为止)
  • 对于选出的每个区间,可以利用index计算出前缀和,区间乘积,以及两侧1的个数(左侧0的个数:当前非0数的下标 - 左侧第一个非0数的下标 - 1,右侧0的个数:右侧第一个非0数的下标 - 当前非0数的下标 - 1

例如:a:[0,1,1,5,1,3,2,4,1,7,1,99,1,1](第一个数用0占位),那么index:(3, 5, 6, 7, 9, 11),两侧1的个数可以利用下标查计算,第一个非0数下标是index[1]=3,找到他左边第一个非0的数是a[0]=0,左边非0的个数=3-0-1=2,右边非0的个数=5-3-1=1。

3、通过计算补1的个数,就可以计算出使得当前和=积的区间个数,累计入总结果

left:左侧1的数量,right:右侧1的数量

两侧1的数量多的记为large,两侧1的数量少的记为small

delt:积-和

分类讨论

        1、0 ≤ delt ≤ small

左侧补0个1,右侧补 delt个1;

左侧补一个1,右侧补delt-1个1;

以此类推,到最后一种是左侧补delt个1,右侧补0个1。

总共有delt+1种情况。 

        2、small < delt ≤ large

small区间最多补small个1,large区间没有限制,因为delt≤large。只需要考虑small区间,small区间补1的范围是0~small个,所以有small+1种情况。

        3、large< delt < small + large

左右两侧区间都没有限制,small区间补1的范围是delt-large~small个,区间情况数:samll+large-delt-1

时间复杂度:O(n)

代码 (版本1)

from collections import deque
n = int(input())
a = [0] + list(map(int, input().split()))
big_1 = deque()
s = [0]

def count_num(delt, left, right):        # 计算补1的区间情况数
    small = min(left, right)
    large = max(left, right)
    if delt < 0 or delt > small + large:
        return 0
    elif delt <= small:
        return delt + 1
    elif delt <= large:
        return small + 1
    return small + large - delt + 1

for i in range(1, n + 1):
    s.append(s[-1] + a[i])                  # 计算区间和
    if a[i] > 1:
        big_1.append(i)
res = n - len(big_1)                        # 计算单独是1的区间
big_1.append(n + 1)                         # 判断最后一个时不需要特判
last_l = 0

# 计算非单独是1的区间
while len(big_1) > 1:
    l = big_1[0]                             # 左端点从队列第一个开始
    cmul = 1
    for i in range(min(len(big_1) - 1, 36)): # 右端点遍历所有非0数/前35个非0数
        r = big_1[i]·                 
        cmul *= a[r]                         # 区间积
        csum = s[r] - s[l - 1]               # 区间和
        if cmul >= csum:                     # 如果区间积>区间和
            delt = cmul - csum               # 积-和
            cl = l - last_l - 1              # 左侧0的个数
            cr = big_1[i + 1] - r - 1        # 右侧0的个数
            res += count_num(delt, cl, cr)
    last_l = l
    big_1.popleft()    # 弹出非0队列的队头
print(res)

代码(版本2) 

from collections import deque

def count(left, right, delt):
    min, max = left, right
    if min > max:
        min, max = max, min
    total = left + right
    if delt < 0 or delt > total:
        return 0
    if delt <= min:
        return delt + 1
    if delt >= max:
        return total - delt + 1
    return min + 1

sum = [0]
s = lambda l, r: sum[r] - sum[l - 1]            #匿名函数算区间和
index = deque()

if __name__ == '__main__':
    n = int(input())
    a = [None] + [int(x) for x in input().split()]
    for i in range(1, n + 1):
        sum.append(sum[-1] + a[i])
        if a[i] > 1:
            index.append(i)
    ans = n - len(index)
    index.append(n + 1)
    last_l = 0
    while len(index) > 1:
        l = index[0]
        p = 1
        upper = min(len(index) - 1, 36)     # number of not 1 < 36
        for i in range(upper):
            r = index[i]
            r_next = index[i + 1]
            p *= a[r]
            delt = p - s(l, r)              #中间的1已经在s(l,r)里算出来了,只要看两边的1
            left = l - last_l - 1
            right = r_next - r - 1
            ans += count(left, right, delt)
        last_l = l
        index.popleft()
    print(ans)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/191030.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vue】模板语法——文本插值

一、模板语法什么是模板语法Vue 使用一种基于 HTML 的模板语法&#xff0c;使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML&#xff0c;可以被符合规范的浏览器和 HTML 解析器解析。在底层机制中&#xff0c;Vue 会将模板编…

(十四)docker安装nacos

一、简介 操作系统&#xff1a;Linux CentOS 7.3 64位 docker版本&#xff1a;19.03.8 nacos版本&#xff1a;默认拉取最新版本 二、实践 1、拉取镜像 docker pull nacos/nacos-server 2、运行容器 docker run --name nacos -p 8848:8848 \ --privilegedtrue \ --restar…

二、什么是GStreamer

GStreamer是一个用于创建流媒体应用程序的框架。基本的设计来自俄勒冈研究生院的视频管道&#xff0c;还有一些来自DirectShow的想法。 GStreamer的开发框架使编写任何类型的流媒体应用程序成为可能。GStreamer框架旨在使编写处理音频或视频或两者同时处理的应用程序变得容易。…

01_学习springdoc的基本使用

文章目录1 什么是 springdoc ?2 springdoc 基本信息3 maven 依赖4 正文来袭4.1 给 Controller 加注解4.2 给 Model 加注解5 大功告成1 什么是 springdoc ? 网上冲浪&#x1f3c4;&#x1f3fb;‍♂️时&#xff0c;无意间发现 java web 应用程序的在线接口文档&#xff0c;除…

开源大数据分析平台的内容有什么?

在大数据时代&#xff0c;做好数据管理是非常重要的一个步骤。可以给企业做出正确的经营决策&#xff0c;指引新的发展方向。因此&#xff0c;随着数字化时代的到来&#xff0c;很多企业都倾向于寻找适宜的开源大数据分析平台&#xff0c;以此提升企业办公协作效率&#xff0c;…

【184】Win10下Java8调用Python的face_recognition库来实现人脸识别

前言 face_recognition 是一个开源的、人脸识别的Python库。本文讲解了在 Windows 10操作系统上&#xff0c;使用 Java8 来调用 Python 的 face_recognition 库来实现人脸识别。虽然 Java8 有 Jython&#xff0c;但是由于截至发文时 Jython 支持的版本太老&#xff08;只有Pyt…

oracle——列表分页查询(原理)

文章目录前言数据表的准备分页sql1、简单分页实现2、排序分页3、排序优化前言 在平时的开发中&#xff0c;Oracle的分页查询用的特别多&#xff0c;接下来不止是说使用&#xff0c;更讲分页sql写法的原理。 数据表的准备 创建一张数据表&#xff0c;并填充大量的数据。 cre…

大数据技术架构(组件)12——Hive:判断函数

1.4.6、判断函数1.4.6.1、ifselect if(11,a,b),if(12,a,b) ;1.4.6.2、isnullselect isnull(1),isnull(null);1.4.6.3、isnotnullselect isnotnull(1),isnotnull(null);1.4.6.4、nvlselect nvl(1,1),nvl(null,1);1.4.6.5、coalesceselect coalesce(1,null,2,3,null,4,null),coal…

感谢第三弹 | 开启地铁国产化浪潮 GBASE获多方城市“地下动脉”肯定

岁末年初&#xff0c;GBASE收到了来自深圳地铁、高新现代智能系统股份有限公司、深圳达实智能股份有限公司等客户及合作伙伴发来的荣誉证书及感谢信。作为亲密无间的战友&#xff0c;GBASE携手高新现代、达实智能在深圳地铁CLC、ACC、AFC多个条线项目中通力合作&#xff0c;助力…

背包问题学习

01背包 01背包&#xff08;0-1 Knapsack Problem&#xff09; 有NNN件物品和一个容量为VVV的背包。放入第iii件物品耗费的费用是CiC_iCi​,得到的价值为WiW_iWi​。求解将哪些物品装入背包可以使价值总和最大 设F[i,v]F\left[i,v\right]F[i,v]表示前iii件物品敲好放入一个容量…

软件防错设计

出现非预期错误的原因解决方案原理介绍断根原理原理&#xff1a;将可能造成人错误的原因/条件从根本上排除断绝掉。通过冗余设计&#xff0c;屏蔽掉其中9种错误的方式&#xff1b;案例&#xff1a;USB的SD卡防写开关。4种可能性断根设计为只有1种可能是正确的。软件设计&#x…

Linux学习之环境准备【Vm+Centos】

文章目录前言一 VMware Workstation17 Pro下载和安装1.1 Vm下载指南1.2 VM安装指南二 Centos7安装2.1 装机器2.2 装系统三 补充内容3.1 卸载Centos前言 工欲善其事&#xff0c;必先利其器&#xff0c;我们要学习Linux当然需要Linux的环境由于大部分人使用的是Windows系统无法进…

介绍OAuth2

目录 一、什么是OAuth2&#xff1f; 二、OAuth2中的角色 1、资源所有者 2、资源服务器 3、客户 4、授权服务器 三、认证流程 四、OAuth2授权方式 注&#xff1a;使用令牌方式的优点 1、授权码 2、隐藏方式 3、密码方式 4、凭证方式 一、什么是OAuth2&#xff1f…

深入浅出ConcurrentHashMap1.8

前言 HashMap是我们平时开发过程中用的比较多的集合&#xff0c;但它是非线程安全的&#xff0c;在涉及到多线程并发的情况&#xff0c;进行get操作有可能会引起死循环&#xff0c;导致CPU利用率接近100%。 final HashMap<String, String> map new HashMap<String,…

基于Springboot搭建java项目(二十四)——权限认证框架SpringSecurity

权限认证框架SpringSecurity 一、为什么要做权限认证 在WEB开发的过程当中&#xff0c;安全一直是很重要的一方面。安全和直接的业务是没有直接挂钩的&#xff0c;但是在业务实现的初期如果没有考虑的安全性的化&#xff0c;在后期迭代的时候就会出现很多的问题。例如存在着安…

4.1--贪心--活动安排问题

今天开始&#xff0c;快速过一遍贪心&#xff0c;贪心要比动态规划简单许多&#xff0c;但是&#xff0c;我们也要理解其中的证明过程 贪心算法采用自顶向下&#xff0c;以迭代的方法做出相继的贪心选择&#xff0c;每做一次贪心选择就将所求问题简化为一个规模更小的子问题&am…

Maven实战-3.setting.xml标签说明

前言 持续更新中… setting.xml文件 1.<localRepository> 自定义本地Maven仓库目录地址。 这样本地的仓库地址就是配置的目录了。 2.<proxies> 基于安全因素考虑&#xff0c;使用通过安全认证的代理访问因特网&#xff0c;这时候需要为Maven配置HTTP代理&…

TOOM大数据舆情监控系统方案,如何做好舆情大数据监测分析?

大数据舆情监控是指通过对大量数据的收集、分析和处理&#xff0c;了解舆论的发展趋势和活动&#xff0c;并对舆论风险进行预警和评估&#xff0c;以保障企业的舆论安全。TOOM大数据舆情监控系统方案&#xff0c;如何做好舆情大数据监测分析? 一、大数据舆情监控系统方案 1.…

车载以太网 - SomeIP - SomeIP Entry - 04

前面总纲内容有说,车载以太网中的SomeIP内容是非常多的,并且为了实现SOA的相关需求,提供了多种多样的报文类型,因此也就有了今天要说的SomeIP-SD中的重要组成部分之一的条目(Entry)部分,而SomeIP-SD在车载网络中占有相当大的比重,可以当做是一定要实现的,如果这块不实…

C语言知识点复习------排序法(冒泡、选择、插入)与链表

目录 排序 冒泡排序&#xff1a; 选择排序&#xff1a; 插入排序&#xff1a; 链表 单链表的建立 单向循环链表的建立 双向循环链表 排序 冒泡排序&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;也是一种简单直观的排序算法。它重复地走访过要排序的数列&a…