蓝桥杯第1595题——和与乘积

题目描述

给定一个数列 A=(a1​,a2​,⋯,an​),问有多少个区间 [L,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。

作者题解

通过题意可以知道,我们其实就是想要找到满足区间和等于区间积的区间个数,根据评测用例规模我们不难发现,如果暴力计算从任意一个数开始的任意长度的区间,一定会超时。

暴力计算除了超时,还有一个问题就是,乘积的变化是非常巨大的。虽然我们可以考虑到使用大数类,但不妨我们考虑一下,如果满足要求的结果是区间积等于区间和,那么如果从某个时刻起,区间积已经比理论区间和的最大值还要大了,是不是就可以停下来了,那么不难发现,理论区间和最大值就是2e5 * 2e5。

进一步思考,既然区间积的变化速度那么快,即便只有2,连续起来的增长速度也远超区间和的增长速度,而区间积的增长速度要想比区间和慢,使最终达到平衡,那就只有1这个值是满足要求的。

于是我们便可以从1这个数值开始考虑,我们不难发现,在新加入区间的数值里,如果加入1,会使得区间和变大,而区间积不变;如果加入其他数值,则不可控。这就给了我们启示,总结一下就是:

如果某个区间的区间和比区间积要小,那么只要在这个区间的左右两边填充足够数量的1,就可以使得区间和等于区间积。

由此我们便可以想到,什么样的区间可以在左右两边加1呢,我们只要收集所有不是1的数的下标,由此进行遍历查找,是不是就可以找到每个左右两边可以填充1的区间了。

区间和我们可以使用前缀和直接拿到,而只考虑非1的数还有一个好处,就是计算区间积的时候我们同样可以忽略1的存在,只对非1的数做乘法运算,因为乘1不会影响区间积。

编码思路

具体的,我们可以在读取数据的时候使用pre数组记录前缀和,便于我们计算区间和。

我们可以创建一个动态数组ArrayList记录所有不为1的数据下标;并且在其前面加上数值0,末尾加上数值n+1,其目的是为了方便计算整段数据首尾的1的个数。

ans的计算也尤为关键,假设我们查询的某个区间刚好区间和等于区间积,那么两侧加1都会导致区间和变大而区间积不变,此时两侧的1就是多余的,仅对ans做++运算即可。

假设此时我们区间和小于区间积,那么意味着可以通过两侧补1的方式实现相等,那么就要具体分析并分类讨论:

现在令左边有left个1,右边有right个1,而我们需要need个1。

如果左右两侧的1数量足够多,那么任意一侧都可以填充(0,1,2,...need)个1来满足要求,总共就是need+1个区间。

如果只有一侧的1数量足够多,那么1的数量较少的区间便成为了我们的限制,于是满足要求的区间数量就变成了min(left, right)+1个区间,原理跟上面的差不多。

那么如果两侧的1数量都不是足够多,但加起来又足以满足need,那么多出来的1的个数便成为了我们的限制;假设left+right刚好等于need,那么我们就只有一种区间选取方式,而不论任意一侧多余出来了一个1,我们可以选取的区间就有了左/右移动一个位置的可能性。

于是我们可以想到,在上述这种情况下,满足要求的区间数量为:left+right-need+1

具体代码

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;public class Main {public static void main(String[] args) throws Exception{BufferedReader in = new BufferedReader(new InputStreamReader(System.in));String[] temp = in.readLine().split(" ");int n = Integer.parseInt(temp[0]);// data表示原始数据int[] data = new int[n + 1];// pre记录前缀和long[] pre = new long[n + 1];// list用于记录非1数据的下标ArrayList<Integer> list = new ArrayList<>();// 首部加0,尾部加n+1,是为了方便计算首尾1的个数list.add(0);temp = in.readLine().split(" ");for (int i = 1; i <= n; i++) {data[i] = Integer.parseInt(temp[i - 1]);pre[i] = pre[i - 1] + data[i];if (data[i] != 1) {list.add(i);}}list.add(n + 1);// 以下是具体算法部分long ans = 0;// 遍历list除了首尾部分的剩余内容,其指的是非1的数据下标for (int i = 1; i < list.size() - 1; i++) {// s表示的区间积// 每次遍历时,s都默认是i所在的位置值,并且先不考虑单个数构成的区间long s = data[list.get(i)];for (int j = i + 1; j < list.size() - 1; j++) {// 随着j每往后移动到一个新的不为1的位置,s需要进行更新s *= data[list.get(j)];// 如果s大于区间和理论最大值,就不必再计算了// 由于区间积的增长速度很快,所以这个优化很关键// 具体的说,可以使内层循环j的运行次数绝对低于log2(2e5 * 2e5),差不多是35左右if (s > 2e5 * 2e5) {break;}// sum记录当前考虑的不为1的数之间的区间和,注意细节不要写错long sum = pre[list.get(j)] - pre[list.get(i) - 1];if (sum <= s) {if (sum == s) { //如果sum刚好和区间积相等,满足要求的区间只会增加1个ans++;} else {    // 如果有多的,分类讨论// left记录左边1的个数,right记录右边1的个数,need表示需要1的个数int left = list.get(i) - list.get(i - 1) - 1;int right = list.get(j + 1) - list.get(j) - 1;long need = s - sum;if (left >= need && right >= need){         // 如果两侧的1都足够多,就有need+1种选取方式ans += need + 1;} else if (left >= need || right >= need) { // 如果只有一侧1足够多ans += Math.min(left, right) + 1;} else if (left + right >= need) {          // 如果两侧都不足够多,但加起来还是够用了ans += left + right - need + 1;}// 如果两侧加起来都不够need,那就直接忽略}}}}// 我们计算的时候忽略了所有单数据区间,而但数据区间一定满足要求,于是加上n进行输出System.out.println(ans + n);}
}

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

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

相关文章

java面试题(持续更新.. ...)

JDK和JRE和JVM区别 JVM是运行字节码的虚拟机&#xff0c;JRE在JVM的基础上添加了基本的类库&#xff0c;JDK在JRE的基础上添加了一些编译的工具(例如&#xff1a;javac等)… … java和c的区别 java和c都是面向对象都支持继承&#xff0c;但是c是多继承&#xff0c;java是单继承…

【硬件工程师面经整理31_非技术问答(主管面)】

文章目录 为什么要来XX对这个岗位工作的了解你期待一个怎么样的工作环境工作强度大/是否愿意加班&#xff0c;怎么看压力大的时候怎么办&#xff1f;个人优势/性格优缺点。团队协作你觉得最重要的是什么未来有什么职业规划如果都给你发了offer你会怎么选&#xff1f;期待的年薪…

安塔利斯升级php8

1、includes/classes/class.Database.php 255行 multi_query方法加返回类型 :bool query方法加返回类型&#xff1a;: mysqli_result|bool 2、includes/classes/class.Session.php on line 91 Optional parameter $planetID declared before required parameter $dpath is…

漏洞发现-漏扫项目篇NucleiYakitGobyAfrogXrayAwvs联动中转被动

知识点 1、综合类-Burp&Xray&Awvs&Goby 2、特征类-Afrog&Yakit&Nuclei 3、联动类-主动扫描&被动扫描&中转扫描 章节点&#xff1a; 漏洞发现-Web&框架组件&中间件&APP&小程序&系统 扫描项目-综合漏扫&特征漏扫&被动…

遥感云计算的一个拐点

GeoForge&#xff0c;一个值得关注的遥感大数据应用 简介 GeoForge是由Ageospatial公司开发的一个基于大语言模型(GeoLLMs)的地理空间分析平台。GeoForg的目的是使每个人都可以轻松进行地图绘制和地理空间分析&#xff0c;无论您是外行还是专家。 Geo for ChatGPT 作者团队已…

win10 蓝牙耳机连接异常重置

安装修复工具 BluetoothCLTools-1.2.0.56 一直下一步 安装完成后管理员进入powershell 执行 btpair.exe -u此命令是卸载蓝牙设备 然后在蓝牙面板和设备管理中查找蓝牙设备是否还在 重新再识别连接蓝牙即可

Three.js显示光源

在做Three.js开发的时候&#xff0c;它本身是不显示光源的&#xff0c;这就很难受&#xff0c;往往加了光源&#xff0c;找不到它放置的位置。 three.js本身不显示光源&#xff0c;可以通过其他方式显示&#xff0c;在光源的防止位置上加一个球即可 function createLightHelper…

Quartz的分布式功能化设计

Quartz的分布式功能化设计 文章目录 Quartz的分布式功能化设计主体功能实现依赖API例子JOBJob记录表设计java具体代码DateDOOperatorDOSysQuartzJobDOPageDTOQuartzJobDTOQuartzJobPageDTOQuartzJobStatusEnumQuartzJobControllerIQuartzJobServiceQuartzJobServiceImplQuartzJ…

YOLOv9改进 添加新型卷积注意力框架SegNext_Attention

一、SegNext论文 论文地址:2209.08575.pdf (arxiv.org) 二、 SegNext_Attention注意力框架结构 在SegNext_Attention中,注意力机制被引入到编码器和解码器之间的连接中,帮助模型更好地利用全局上下文信息。具体而言,注意力机制通过学习像素级的注意力权重,使得模型可以对…

深度解析react中hooks的底层原理是啥?React架构原理深度解析

1.React Hooks 底层原理 React Hooks 的底层原理是基于 React Fiber 架构的实现。下面是对 React Hooks 底层原理的深度解析: Fiber 架构: React Fiber 是 React 的新的协调引擎,它的设计目标是支持增量式更新、优先级调度、暂停和继续执行等特性。Fiber 架构重新实现了 Re…

FFmpeg开发笔记(十)Linux环境给FFmpeg集成vorbis和amr

FFmpeg内置了aac音频格式&#xff0c;在《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书的“5.2.2 Linux环境集成mp3lame”又介绍了如何给FFmpeg集成mp3格式&#xff0c;常见的音频文件除了这两种之外&#xff0c;还有ogg和amr两种格式也较常用。其中ogg格式的编解码…

【C++庖丁解牛】vector容器的简易模拟实现(C++实现)(最后附源码)

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 前言vector容器代码实现内…

前端JavaScript篇之常见事件

目录 JavaScript常见事件click&#xff08;点击&#xff09;mouseover&#xff08;鼠标悬停&#xff09;keydown&#xff08;按键按下&#xff09;load&#xff08;加载&#xff09;submit&#xff08;提交&#xff09; JavaScript常见事件 JavaScript中的事件是指用户与网页元…

python基础13_字符编码

什么是字符编码呢? 在讲字符编码的之前,我先讲一个东西叫字符集 什么是字符集呢? python默认的字符集unicode 很简单,就是他把大部分国家的文字,符号,都集合过来,每一个文字或者说是符号都有一个编号去代表 你可以理解成高考 每个考生的准考证号,就代表这个学生 那么字…

JVM垃圾收集器-serial.parNew,parallelScavnge,serialOld,parallelOld,CMS,G1

垃圾收集器 分代模型 适用于新生代&#xff1a; serial parNew parallel Scaavenge 适用于老年代&#xff1a; CMS serial Old(msc) paraller Old 分区模型 适用于超大容量&#xff1a; G1 分代模型 serial /serial Old收集器 1.单线程收集器 2.收集时会暂停其他线程&…

剑指offer C ++双栈实现队列

1. 基础 队列&#xff1a;先进先出&#xff0c;即插入数据在队尾进行&#xff0c;删除数据在队头进行&#xff1b; 栈&#xff1a;后进先出&#xff0c;即插入与删除数据均在栈顶进行。 2. 思路 两个栈实现一个队列的思想&#xff1a;用pushStack栈作为push数据的栈&#xff…

使用canvas绘制超炫时钟

HTML5 Canvas相当于一个画板&#xff0c;你可以在Canvas绘制任意的东西&#xff0c;今天要分享一款利用HTML5 Canvas绘制的超炫时钟的方法及代码&#xff0c;非常的漂亮&#xff0c;这里推荐给大家 代码地址 使用canvas绘制超炫时钟

react中JSX的详解

目录 JSX的本质及其与JavaScript的关系探究 一、JSX的本质 二、JSX与JavaScript的关系 三、为什么要使用JSX 四、不使用JSX的后果 五、JSX背后的功能模块 JSX的本质及其与JavaScript的关系探究 在React开发中&#xff0c;JSX是一个不可或缺的部分。那么&#xff0c;JSX的…

LeetCode102题:二叉树的层序遍历(python3)

代码思路&#xff1a;使用队列先进先出的特性&#xff0c;queue[]不为空进入for循环&#xff0c;tmp存储每层的节点&#xff0c;将结果添加至res[]中。 python中使用collections中的双端队列deque()&#xff0c;其popleft()方法可达到O(1)时间复杂度。 class Solution:def lev…

5.62 BCC工具之cpudist.py解读

一,工具简介 cpudist会将任务在CPU上的时间汇总为直方图,显示任务在被取消调度之前在CPU上花费的时间。这提供了有价值的信息,可以指示过度订阅(处理器太少而任务太多)、由于过多上下文切换而产生的开销(例如,多个线程共用的常见锁)、工作负载分布不均、任务过于细化等…