好数——前缀和思想(题目分享)

        今天我的舍友去参加“传智杯”广东省的省赛,跟我说了这样一道题,他说他想不出来怎么去优化代码,怎么做都是套用两层for循环超时,下面我就根据题意,使用前缀和的算法去优化一下思路,题目本身是不难的,请看思路:

题意:

示例

输入:
2
5
1 2 3 4 5
4
12 14 16 18 20
3
1 1 5
2 2 4
1 3 5
输出:
2
1
1
解释:
  • 对于第一组数组 [1, 2, 3, 4, 5]

    • 下标 [1,5][1,5] 范围内的“好数”是 22 和 44,共 22 个。

  • 对于第二组数组 [12, 14, 16, 18, 20]

    • 下标 [2,4][2,4] 范围内的“好数”是 1414,共 11 个。

  • 对于第一组数组 [1, 2, 3, 4, 5]

    • 下标 [3,5][3,5] 范围内的“好数”是 44,共 11 个。

算法代码:

#include <iostream>  // 包含输入输出流库,用于标准输入输出
#include <vector>    // 包含向量库,用于动态数组操作
#include <cmath>     // 包含数学库,用于sqrt等数学函数using namespace std; // 使用标准命名空间,避免std::前缀// 计算一个数的因数和(不包括它本身)
int sum_of_factors(int x) {if (x == 1) return 0; // 1 没有其他因数int sum = 1; // 1 是所有数的因数for (int i = 2; i < x; ++i) { // 遍历 2 到 x-1if (x % i == 0) { // 如果 i 是 x 的因数sum += i; // 将 i 加到 sum 中}}return sum; // 返回因数和
}// 判断一个数是否为“好数”
bool is_good_number(int x) {int sum = sum_of_factors(x); // 计算x的因数和return (sum * x) % 2 == 0; // 判断(sum * x)是否为偶数,是则返回true,否则返回false
}// 预处理函数,生成前缀和数组
vector<int> preprocess(const vector<int>& arr) {vector<int> prefix(arr.size() + 1, 0); // 初始化前缀和数组,大小为arr.size()+1,初始值为0for (size_t i = 0; i < arr.size(); ++i) { // 遍历数组arrprefix[i + 1] = prefix[i] + (is_good_number(arr[i]) ? 1 : 0); // 计算前缀和,如果arr[i]是“好数”,则加1,否则加0}return prefix; // 返回前缀和数组
}int main() {int t;cin >> t; // 输入数组的组数vector<vector<int>> arrays(t); // 定义二维数组arrays,存储t组数组vector<vector<int>> prefixes(t); // 定义二维数组prefixes,存储每组数组的前缀和// 输入每组数组并预处理for (int i = 0; i < t; ++i) { // 遍历每组数组int s;cin >> s; // 输入当前数组的大小arrays[i].resize(s); // 调整当前数组的大小为sfor (int j = 0; j < s; ++j) { // 遍历当前数组的每个元素cin >> arrays[i][j]; // 输入当前数组的元素}prefixes[i] = preprocess(arrays[i]); // 对当前数组进行预处理,生成前缀和数组}int b;cin >> b; // 输入查询次数// 处理每次查询for (int i = 0; i < b; ++i) { // 遍历每次查询int group, l, r;cin >> group >> l >> r; // 输入查询的数组组号和范围[l, r]// 假设输入的l和r是从1开始的,需要转换为从0开始l--; // 将l转换为从0开始的下标r--; // 将r转换为从0开始的下标// 使用前缀和数组快速计算范围内的“好数”个数int good_count = prefixes[group - 1][r + 1] - prefixes[group - 1][l]; // 计算区间[l, r]内“好数”的个数cout << good_count << endl; // 输出结果}return 0; // 程序正常结束
}

代码思路

1. 问题分析

  • 题目要求处理多组数组,每组数组包含若干整数。

  • 对于每组数组,需要多次查询某个区间 [l, r] 内“好数”的个数。

  • “好数”的定义是:一个数的所有因数(不包括它本身)的和乘以它本身,结果为偶数。

2. 核心需求

  • 高效计算每个数的因数和。

  • 快速判断一个数是否为“好数”。

  • 对每组数组进行预处理,支持快速查询区间内“好数”的个数。

3. 设计思路

  • 因数和计算:通过遍历 2 到 sqrt(x),找到所有因数并累加。

  • 好数判断:根据因数和与数本身的乘积是否为偶数来判断。

  • 前缀和预处理:对每组数组生成前缀和数组,用于快速查询区间内“好数”的个数。

  • 查询优化:利用前缀和数组,将每次查询的时间复杂度降低到 O(1)


代码逻辑分步解析

1. 头文件和命名空间

#include <iostream>  // 标准输入输出库
#include <vector>    // 动态数组库
#include <cmath>     // 数学函数库(如sqrt)
using namespace std; // 使用标准命名空间
  • 包含必要的库文件,并简化代码中的命名空间。这里我还是建议直接使用万能头文件,毕竟不是写项目,不会出错,而且还节约时间。

    #include<bits/stdc++.h>

2. 因数和计算

int sum_of_factors(int x) {if (x == 1) return 0; // 1 没有其他因数int sum = 1; // 1 是所有数的因数for (int i = 2; i < x; ++i) { // 遍历 2 到 x-1if (x % i == 0) { // 如果 i 是 x 的因数sum += i; // 将 i 加到 sum 中}}return sum; // 返回因数和
}
  • 功能:计算一个数的因数和(不包括它本身)。

  • 优化:通过遍历到 sqrt(x),减少计算量。


3. 好数判断

bool is_good_number(int x) {int sum = sum_of_factors(x); // 计算 x 的因数和return (sum * x) % 2 == 0; // 判断 (sum * x) 是否为偶数
}
  • 功能:判断一个数是否为“好数”。

  • 逻辑:根据因数和与数本身的乘积是否为偶数来判断。


4. 前缀和预处理

vector<int> preprocess(const vector<int>& arr) {vector<int> prefix(arr.size() + 1, 0); // 初始化前缀和数组for (size_t i = 0; i < arr.size(); ++i) { // 遍历数组prefix[i + 1] = prefix[i] + (is_good_number(arr[i]) ? 1 : 0); // 计算前缀和}return prefix; // 返回前缀和数组
}
  • 功能:生成前缀和数组,用于快速查询区间内“好数”的个数。

  • 逻辑

    • prefix[i] 表示数组前 i 个元素中“好数”的个数。

    • 如果 arr[i] 是“好数”,则前缀和加 1,否则加 0。


5. 主函数逻辑

int main() {int t;cin >> t; // 输入数组的组数vector<vector<int>> arrays(t); // 存储 t 组数组vector<vector<int>> prefixes(t); // 存储 t 组前缀和
  • 功能:初始化存储数组和前缀和的数据结构。


6. 输入数组并预处理

for (int i = 0; i < t; ++i) { // 遍历每组数组int s;cin >> s; // 输入当前数组的大小arrays[i].resize(s); // 调整数组大小for (int j = 0; j < s; ++j) { // 遍历数组元素cin >> arrays[i][j]; // 输入数组元素}prefixes[i] = preprocess(arrays[i]); // 预处理生成前缀和
}
  • 功能:输入每组数组,并生成对应的前缀和数组。


7. 处理查询

int b;
cin >> b; // 输入查询次数
for (int i = 0; i < b; ++i) { // 遍历每次查询int group, l, r;cin >> group >> l >> r; // 输入查询的数组组号和范围l--; // 将 l 转换为从 0 开始的下标r--; // 将 r 转换为从 0 开始的下标int good_count = prefixes[group - 1][r + 1] - prefixes[group - 1][l]; // 计算区间内“好数”的个数cout << good_count << endl; // 输出结果
}
  • 功能:处理每次查询,输出区间内“好数”的个数。

  • 逻辑

    • 将用户输入的 l 和 r 转换为从 0 开始的下标。

    • 使用前缀和数组快速计算区间 [l, r] 内“好数”的个数。


8. 程序结束

return 0; // 程序正常结束
  • 功能:表示程序执行成功并结束。


总结

  • 核心思想:通过预处理和前缀和优化查询性能。

  • 时间复杂度

    • 预处理:O(t * s * sqrt(M)),其中 t 是组数,s 是数组大小,M 是数组中最大数。

    • 查询:O(b),其中 b 是查询次数。

  • 空间复杂度O(t * s),用于存储数组和前缀和。

通过这种设计,代码能够高效处理大规模数据,并满足题目对时间的要求。

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

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

相关文章

记录uniapp小程序对接腾讯IM即时通讯无ui集成(2)

完成以上步骤之后开始进行登录&#xff0c;登陆就需要账号。这个账号我们可以在腾讯云中创建。 有了账号之后开始去小程序进行登陆操作。腾讯云接口文档 这里除了帐号还需要一个校验值userSig正常项目开发这个字段可以在登陆后让后端返回&#xff0c;现在是测试我们直接去控制…

智能指针的使用和原理

目录 C标准库智能指针的使用 auto_ptr的了解 unique_ptr的了解 shared_ptr的了解 应用 析构问题 解决办法 方案一&#xff1a;特化 方案二&#xff1a;删除器 智能指针原理 shared_ptr循环引用问题 了解weak_ptr shared_ptr的线程安全问题 内存泄漏 如何避免内存…

【北上广深杭大厂AI算法面试题】深度学习篇...这里详细说明ResNet中为什么不用dropout?

【北上广深杭大厂AI算法面试题】深度学习篇…这里详细说明ResNet中为什么不用dropout? 【北上广深杭大厂AI算法面试题】深度学习篇…这里详细说明ResNet中为什么不用dropout? 文章目录 【北上广深杭大厂AI算法面试题】深度学习篇...这里详细说明ResNet中为什么不用dropout?…

stm32移植LCD2002驱动

介绍 LCD2002支持20X2个字符串显示&#xff0c;引脚功能和读写时序跟LCD1602都很像 LCD类型&#xff1a;字符点阵 点 阵 数&#xff1a;202 外形尺寸&#xff1a;116.0mm37.0mm&#xff08;长宽&#xff09; 视域尺寸&#xff1a;83.0mm18.6mm 点 距 离&#xff1a;0.05mm…

*动态规划(4)

持续更新 1.入门 ⽤于解决多阶段决策问题的算法思想。它通过将复杂问题分解为更⼩的⼦问题&#xff0c;并存储⼦问题的解&#xff08;通常称为“状态”&#xff09;&#xff0c;从⽽避免重复计算&#xff0c;提⾼效率。因此&#xff0c;动态规划⾥&#xff0c;蕴含着分治与剪枝…

计算机毕业设计SpringBoot+Vue.js社团管理系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

现今大语言模型性能(准确率)比较

现今大语言模型性能(准确率)比较 表头信息:表的标题为“大语言模型性能比较结果”(英文:Table 1: Large Language Model Performance Comparison Results),表明该表是用于对比不同大语言模型的性能。列信息: 模型:列出参与比较的不同大语言模型名称,包括LLAMA3(70B)…

合成复用原则

合成复用原则 也被称为组合复用原则或聚合复用原则。 合成复用原则提倡尽量使用组合或者聚合等关联关系来实现代码复用&#xff0c;而不是通过继承关系来复用代码。组合是一种强的 “拥有” 关系&#xff0c;体现了严格的部分和整体的关系&#xff0c;部分和整体的生命周期一…

Unity 对象池技术

介绍 是什么&#xff1f; 在开始时初始化若干对象&#xff0c;将它们存到对象池中。需要使用的时候从对象池中取出&#xff0c;使用完后重新放回对象池中。 优点 可以避免频繁创建和销毁对象带来性能消耗。 适用场景 如果需要对某种对象进行频繁创建和销毁时&#xff0c;例…

记一次ScopeSentry搭建

介绍 Scope Sentry是一款具有资产测绘、子域名枚举、信息泄露检测、漏洞扫描、目录扫描、子域名接管、爬虫、页面监控功能的工具&#xff0c;通过构建多个节点&#xff0c;自由选择节点运行扫描任务。当出现新漏洞时可以快速排查关注资产是否存在相关组件。 目前功能 插件系…

LeetCode热题100JS(20/100)第四天|​41. 缺失的第一个正数​|​73. 矩阵置零​|​54. 螺旋矩阵​|​48. 旋转图像​

41. 缺失的第一个正数 题目链接&#xff1a;41. 缺失的第一个正数 难度&#xff1a;困难 刷题状态&#xff1a;1刷 新知识&#xff1a; 解题过程 思考 示例 1&#xff1a; 输入&#xff1a;nums [1,2,0] 输出&#xff1a;3 解释&#xff1a;范围 [1,2] 中的数字都在数组中…

ComfyUI+Lumina小试牛刀

序 本文主要研究一下Lumina Image 2.0模型的中文提示词进行文生图。 步骤 安装ComfyUI git clone https://github.com/comfyanonymous/ComfyUI cd ComfyUI python3 -m pip install -r requirements.txt启动ComfyUI python3 -u main.py --listen --port6889 --disable-auto…

我的世界1.20.1forge模组开发进阶物品(7)——具有动画、3D立体效果的物品

基础的物品大家都会做了对吧?包括武器的释放技能,这次来点难度,让物品的贴图呈现动画效果和扔出后显示3D立体效果,这个3D立体效果需要先学习blockbench,学习如何制作贴图。 Blockbench Blockbench是一个用于创建和编辑三维模型的免费软件,特别适用于Minecraft模型的设计…

HarmonyOS NEXT开发进阶(十一):应用层架构介绍

文章目录 一、前言二、应用与应用程序包三、应用的多Module设计机制四、 Module类型五、Stage模型应用程序包结构六、拓展阅读 一、前言 在应用模型章节&#xff0c;可以看到主推的Stage模型中&#xff0c;多个应用组件共享同一个ArkTS引擎实例&#xff1b;应用组件之间可以方…

C++学习之C++初识、C++对C语言增强、对C语言扩展

一.C初识 1.C简介 2.第一个C程序 //#include <iostream> //iostream 相当于 C语言下的 stdio.h i - input 输入 o -output 输出 //using namespace std; //using 使用 namespace 命名空间 std 标准 &#xff0c;理解为打开一个房间&#xff0c;房间里有我们所需…

zabbix配置邮件告警

目录 实现步骤&#xff1a; 实现目的&#xff1a; 1.在监控端操作&#xff1a; 2.web界面部署 ​​​​​​​实现步骤&#xff1a; 1、在 zabbix服务端配置邮件发送脚本和修改 zabbix服务端配置文件; 2、在 zabbix前端控制台进行相关设置。 实现目的&#xff1a; Zab…

Qt显示一个hello world

一、显示思路 思路一&#xff1a;通过图形化方式&#xff0c;界面上创建出一个控件显示。 思路二&#xff1a;通过编写C代码在界面上创建控件显示。 二、思路一实现 点开 Froms 的 widget.ui&#xff0c;拖拽 label 控件&#xff0c;显示 hello world 即可。 qmake 基于 .…

学到什么记什么(25.3.3)

Upload-labs 今日重新做了一下文件上传漏洞&#xff0c;这里第一题之前采用直接抓包改后缀名.jpg为.php&#xff0c;再写入一句话<?php phpinfo();?>然后放行&#xff0c;得到图片地址&#xff08;可复制&#xff09;&#xff0c;本来直接访问图片地址即可得到敏感信息…

Keepalived 入门详解:高可用集群部署最佳实践!

1. 什么是 Keepalived&#xff1f; 在分布式集群中&#xff0c;单点故障&#xff08;SPOF&#xff09; 是影响系统稳定性的重要问题。Keepalived 作为一款高可用服务软件&#xff0c;可以有效防止集群单点故障&#xff0c;保障系统的高可用性。 Keepalived 最初是为 LVS&#…

宝塔找不到php扩展swoole,服务器编译安装

1. 在php7.4中安装swoole&#xff0c;但找不到这个扩展安装 2. 服务器下载源码解压安装 http://pecl.php.net/package/swoole 下载4.8.0版本 解压到/www/server/php/74/下 3. 发现报错问题&#xff1b; 更新一下依赖 yum update yum -y install gcc gcc-c autoconf libjpe…