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

【备战秋招】每日一题:2023.03.26-阿里OD机试(第三题)-数组之和最小值

为了更好的阅读体检,可以查看我的算法学习网站
在线评测链接:P1119

题目内容

塔子哥是一个热爱数学的年轻数学家,他对数字和因子分解有着深入的研究。

有一天,他在一次偶然的探索中发现了一款神奇的游戏,名为“除数游戏”。

在这个游戏中,玩家需要在一个整数数组 a a a 中选择一个大于 1 1 1的数字 a i a_i ai ,并将其除以其中一个素因子 p p p (素因子是能被 a i a_i ai 整除的素数)。接着,玩家可以继续将新数字除以素因子,直到进行了 k k k 次操作。

塔子哥很快就意识到,这个游戏可以为他的研究提供很多有用的信息。他开始探究在最多进行 k k k 次操作的情况下,玩家能够通过该游戏达到的最小数组总和是多少?

输入描述

第一行输入两个正整数 n n n k k k,代表数组大小以及操作次数。

第二行输入 n n n个正整数 a i a_i ai,代表数组的元素。

1 ≤ n , k ≤ 200000 1\leq n,k\leq 200000 1n,k200000

1 ≤ a i ≤ 1 0 6 1\leq a_i\leq 10^6 1ai106

输出描述

一个整数,代表操作后的所有元素最小的和。

样例

输入

5 2
1 2 3 4 5

输出

9

思路

贪心+优先队列+数论优化

1.贪心策略:由于要最小化数组的总和,那么对于某一个数 a i a_i ai , 要除一定是除它最大的质因子 m a x f a c t o r ( a i ) maxfactor(a_i) maxfactor(ai)。 这样下降的最多,下降量为: Δ i = a i − m a x f a c t o r ( a i ) \Delta_i = a_i - maxfactor(a_i) Δi=aimaxfactor(ai) 。所以显然每一次操作我们肯定是选择 m a x ( Δ i ) max(\Delta_i) max(Δi) 的位置 i i i 。然后还需要更新这个值。

2.引入高级数据结构:数据量比较大,为了能够快速实现我们这个贪心策略,我们需要一个可以快速 1.寻找最大值 2.删除最大值 3.插入值 的数据结构。这个显然可以使用优先队列维护。

3.引入数论优化:在优先队列的排序过程中,由于我们需要获取 m a x f a c t o r maxfactor maxfactor , 这个东西如果每次都暴力获得,复杂度为 O ( V ) O(\sqrt{V}) O(V ) ,那么导致总复杂度为 O ( k ∗ l o g n ∗ V ) O(k*log n * \sqrt{V}) O(klognV ) 。 这是不可接受的(虽然期望复杂度无法达到这么高,但是我们总是希望有更优的解法!)。所以我们需要先预处理出 [ 1 , V = 1 e 6 ] [1,V=1e6] [1,V=1e6] 中的所有数的 m a x f a c t o r ( i ) maxfactor(i) maxfactor(i)

这个预处理方法,我们可以直接使用埃式筛的方法,转移伪代码如下:

for i in 2 ... V:if maxfactor[i] : continuefor j in i -> V , step = imaxfactor[j] = max(maxfactor[j] , i)

这样一来,
m a x f a c t o r ( i ) = { 0 i ∈ p r i m e m a x P r i m e F a c t o r o f i o t h e r \Large maxfactor(i)=\left\{\begin{matrix} 0 & i\ \in\ prime\\ maxPrimeFactor\ of\ i & other \end{matrix}\right. maxfactor(i)= 0maxPrimeFactor of ii  primeother

最后,如果用一句话解释这个题的本质,就是TopK变种罢了 , 具体细节见代码!

类似题目推荐

LeetCode

见 贪心 - 代码随想录 . 这个只是入门,刷完也并不意味着能做出这题。

CodeFun2000

提供一些贪心题

P1014 2022.10.8-美团春招-塔子玩游戏

开胃菜1

P1211 塔子大厂真题模拟赛-第一题-魔法石(Ⅰ)

开胃菜2

P1279 2023.05.06-春招-第三题-塔子哥的游戏

同样是贪心 + 优先队列的经典题目!推荐做一做!

P1239 2023.04.20-华为od-第一题-总最快检测效率

同样是贪心 + 优先队列的经典题目!推荐做一做!

P1148 2023.4.3-阿里巴巴-研发岗-第三题-又一个数论题

虽然不是贪心题。但是也是常见算法套上了数论的优化!

代码

CPP

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 +5;
#define ll long long
int f[maxn] , a[maxn];
// 优先队列的节点
struct Node {int x;// 定义顺序bool operator < (const Node & a) const {int g1 = x - x / f[x];int g2 = a.x - a.x / f[a.x];// 优先下降量大的放堆顶return g1 < g2;}
};
priority_queue<Node> q;
int main (){int n , k;// f 就是 上文的maxfactor , 即最大质因数f[1] = 1;for (int i = 2 ; i < maxn ; i++){if (f[i] != 0) continue;for (int j = i ; j < maxn ; j += i){f[j] = max(f[j] , i);}}cin >> n >> k;// 把a[i] 都放入堆,同时获得最大值ll sum = 0;for (int i = 1 ; i <= n ; i++){cin >> a[i];sum += a[i];q.push({a[i]});}// 模拟操作while (k--){// 每次从堆顶拿出下降量最多的元素Node g = q.top();q.pop();// 更新总和sum -= g.x;sum += g.x / f[g.x];// 重新放入堆q.push({g.x / f[g.x]});}// 输出总和cout << sum << endl;return 0;
}

python

from random import *
import sys
from collections import * 
from math import * 
from functools import *
from heapq import *def solve(n,k,arr):mx = max(arr)tot = sum(arr)#f 就是 上文的maxfactor , 即最大质因数f = list(range(mx+1))for i in range(2,mx+1):if f[i] != i: continuefor j in range(i*2,mx+1,i):f[j] = i hq = []# 先把所有元素的可能序列都先全部放到序列中for a in arr:while a > 1:hq.append(a//f[a]-a)a //= f[a]# 建堆heapify(hq)# 取前k大for _ in range(k):if not hq: break tot += heappop(hq)return tot  # 读入
n, k = list(map(int,input().split()))
arr = list(map(int,input().split()))
print(solve(n,k,arr))

Java

import java.util.*;
public class Main {static int MAXN = 1000010;static int[] prime = new int[MAXN];public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int k = sc.nextInt();prime[1] = 1;PriorityQueue<Node> pq = new PriorityQueue<>();isPrime();// 先将n个数放入优先队列for (int i = 0; i < n; i++) {int x = sc.nextInt();Node node = new Node(x, prime[x]);pq.offer(node);}// 模拟while (k-- > 0){Node node = pq.poll();int data = node.data;int x = data / node.prime;pq.offer(new Node(x, prime[x]));}long ans = 0;while (!pq.isEmpty()){ans += pq.poll().data;}System.out.println(ans);}// 求最大素数private static void isPrime() {for (int i = 2; i < MAXN; i++){if (prime[i] == 0){for (int j = i; j < MAXN; j += i){prime[j] = i;}}}}// 自定义排序static class Node implements Comparable<Node>{int data;int prime;public Node(int data, int prime) {this.data = data;this.prime = prime;}@Overridepublic int compareTo(Node o) {// 下降量最大优先return (o.data - o.data / o.prime) - (this.data - this.data / this.prime);}}
}

Go

package mainimport ("container/heap""fmt"
)const maxn = 1e6 + 5type Node struct {x int
}type PriorityQueue []Nodefunc (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {g1 := pq[i].x - pq[i].x/f[pq[i].x]g2 := pq[j].x - pq[j].x/f[pq[j].x]// 优先下降量大的放堆顶return g1 > g2
}
func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] }func (pq *PriorityQueue) Push(x interface{}) {node := x.(Node)*pq = append(*pq, node)
}func (pq *PriorityQueue) Pop() interface{} {n := len(*pq)node := (*pq)[n-1]*pq = (*pq)[:n-1]return node
}var f [maxn]int
var a [maxn]intfunc main() {var n, k int// f 就是 上文的 maxfactor,即最大质因数f[1] = 1for i := 2; i < maxn; i++ {if f[i] != 0 {continue}for j := i; j < maxn; j += i {f[j] = max(f[j], i)}}fmt.Scan(&n, &k)// 把 a[i] 都放入堆,同时获得最大值var sum int64 = 0pq := make(PriorityQueue, n)for i := 0; i < n; i++ {fmt.Scan(&a[i])sum += int64(a[i])pq[i] = Node{a[i]}}heap.Init(&pq)// 模拟操作for i := 0; i < k; i++ {// 每次从堆顶拿出下降量最多的元素g := heap.Pop(&pq).(Node)// 更新总和sum -= int64(g.x)sum += int64(g.x / f[g.x])// 重新放入堆heap.Push(&pq, Node{g.x / f[g.x]})}// 输出总和fmt.Println(sum)
}func max(x, y int) int {if x > y {return x}return y
}

Js

注意:已知的OJ上的JavaScript都不提供优先队列,要手写优先队列,这里塔子哥提供一种实现。

// 基于堆实现优先队列 , 函数名参考Java实现的priorityQueue
class Pqueue {constructor(cpr) {this.queue = [];this.size = 0;this.cpr = cpr;}swap(i, j) {let tmp = this.queue[i];this.queue[i] = this.queue[j];this.queue[j] = tmp;}// 上浮swim() {let ch = this.queue.length - 1;while (ch !== 0) {let fa = Math.floor((ch - 1) / 2);const ch_node = this.queue[ch];const fa_node = this.queue[fa];if (this.cpr(ch_node, fa_node) < 0) {this.swap(ch, fa);ch = fa;} else {break;}}}// 下沉sink() {let fa = 0;while (true) {let ch_left = 2 * fa + 1;let ch_right = 2 * fa + 2;let ch_max;let ch_max_node;const fa_node = this.queue[fa];const ch_left_node = this.queue[ch_left];const ch_right_node = this.queue[ch_right];if (ch_left_node && ch_right_node) {// 注意这里应该要>=0,因为左边优先级高if (this.cpr(ch_left_node, ch_right_node) <= 0) {ch_max = ch_left;ch_max_node = ch_left_node;} else {ch_max = ch_right;ch_max_node = ch_right_node;}} else if (ch_left_node && !ch_right_node) {ch_max = ch_left;ch_max_node = ch_left_node;} else if (!ch_left_node && ch_right_node) {ch_max = ch_right;ch_max_node = ch_right_node;} else {break;}// 注意这里应该要>0,因为父优先级高if (this.cpr(ch_max_node, fa_node) < 0) {this.swap(ch_max, fa);fa = ch_max;} else {break;}}}// 向优先队列中加入元素offer(ele) {this.queue.push(ele);this.size++;this.swim();}// 取出最高优先级元素poll() {this.swap(0, this.queue.length - 1);this.size--;const ans = this.queue.pop();this.sink();return ans;}// 只使用最高优先级元素,不取出peek() {return this.queue[0];}
}// 正片const maxn = 1e6 + 5;
let f = new Array(maxn).fill(0);
let a = new Array(maxn).fill(0);let q = new Pqueue((a , b) => {let g1 = a - Math.floor(a / f[a]);let g2 = b - Math.floor(b / f[b]);return g2 - g1;
});
f[1] = 1;
for (let i = 2; i < maxn; i++) {if (f[i] !== 0) continue;for (let j = i; j < maxn; j += i) {f[j] = Math.max(f[j], i);}
}process.stdin.resume();
process.stdin.setEncoding("utf-8");
let input = "";
process.stdin.on("data", (data) => {input += data;return;
});
process.stdin.on("end", () => {const lines = input.trim().split("\n");var [n, k] = lines[0].split(" ").map(Number);var a = lines[1].split(' ').map(Number);let sum = 0;for (let i = 0 ; i < n; i++) {sum += a[i];q.offer(a[i]);}while (k--) {let x = q.poll();sum -= x;sum += Math.floor(x / f[x]);q.offer(Math.floor(x / f[x]));}console.log(sum);
});

题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除

相关文章:

【备战秋招】每日一题:2023.03.26-阿里OD机试(第三题)-数组之和最小值

为了更好的阅读体检&#xff0c;可以查看我的算法学习网站 在线评测链接:P1119 题目内容 塔子哥是一个热爱数学的年轻数学家&#xff0c;他对数字和因子分解有着深入的研究。 有一天&#xff0c;他在一次偶然的探索中发现了一款神奇的游戏&#xff0c;名为“除数游戏”。 在…...

网站的SEO优化:提升搜索引擎可见性的关键步骤

93. 网站的SEO优化&#xff1a;提升搜索引擎可见性的关键步骤 SEO&#xff08;Search Engine Optimization&#xff09;是指通过优化网站的内容、结构、链接和其他因素&#xff0c;以提高网站在搜索引擎结果页面&#xff08;SERP&#xff09;中的排名和可见性的过程。 优化网…...

Spring Boot 中的服务注册是什么,原理,如何使用

Spring Boot 中的服务注册是什么&#xff0c;原理&#xff0c;如何使用 Spring Boot 是一个非常流行的 Java 后端框架&#xff0c;它提供了许多便捷的功能和工具&#xff0c;使得开发者可以更加高效地开发微服务应用。其中&#xff0c;服务注册是 Spring Boot 微服务架构中非常…...

spring.factories文件在Spring工程中的说明

说明 spring.factories 是 Spring Boot 框架中一个特殊的配置文件&#xff0c;它用于定义自动配置的实现类以及要注册的其他组件信息。该文件通常位于 META-INF/spring.factories 目录下&#xff0c;Spring Boot 在启动时会自动加载它并读取其中的配置信息。 spring.factorie…...

常见的自动化测试架构有哪些?

目录 前言 常见的自动化架构包括如下。 1.数据驱动测试 2.模块驱动测试 3.关键字驱动测试 优点&#xff1a; 缺点&#xff1a; 总结&#xff1a; 前言 一个自动化测试架构就是一个集成体系&#xff0c;其中定义了一个特殊软件产品的自动化测试规则。这一体系中包含测试…...

Revit中用自适应创建简单的瓦片族和切换构件的材质?

一、Revit中使用自适应创建瓦片族 在我们的日常生活中&#xff0c;屋顶的瓦片是我们经常都能够见到的&#xff0c;瓦片能够挡风遮雨也能够使建筑物带来古香古色的气息&#xff0c;那我们今天来学习如何使用自适应创建简单的瓦片族。 1.首先&#xff1a;我们打开自适应公制常规模…...

Spring Boot实战:拦截器和监听器的应用指南

当使用Spring Boot时&#xff0c;我们可以通过拦截器&#xff08;Interceptor&#xff09;和监听器&#xff08;Listener&#xff09;来实现对请求和响应的处理。拦截器和监听器提供了一种可插拔的机制&#xff0c;用于在请求处理过程中进行自定义操作&#xff0c;例如记录日志…...

为什么要搭建数据仓库

数据是企业中最重要的资源之一&#xff0c;因此&#xff0c;随着企业数据量的不断增大和复杂度的提高&#xff0c;建立一个可靠和健全的数据仓库变得越来越重要。在数聚股份看来&#xff0c;一个数据仓库可以作为一个企业数据存储和管理系统&#xff0c;能够更有效地存储、管理…...

Sql Server 获取连续日期时间

获取连续日期时间 在项目中&#xff0c;有时候需要按日期/时间统计&#xff0c;例如2023-06-21至2023-06-28期间每一天的数据&#xff0c;如果某一天没有数据&#xff0c;也要查询出来&#xff0c;用NULL处理。 1.示例 2.连续日期效果SQL DECLARE StartDate DATE 2023-06-2…...

MIT 6.830数据库系统 -- lab two

MIT 6.830数据库系统 -- lab two 项目拉取Lab Two实现提示练习一 -- Filter and Join练习二 -- Aggregates练习三 -- HeapFile Mutability练习四 -- Insertion & deletion练习五 -- Page eviction练习六 -- Query walkthrough练习七 - 查询解析 项目拉取 原项目使用ant进行…...

React基础知识点(一)

React基础知识点 目标 能够说出React是什么能够说出React的特点能够掌握React的基本使用能够使用React脚手架 什么是React &#xff08;★★★&#xff09; React是一个用于构建用户界面的javaScript库&#xff0c;起源于facebook的内部项目&#xff0c;后续在13年开源了出…...

机器学习-进化算法

进化算法 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;crossovermutation 进化策略&#xff08;Evolutionary Strategies&#xff0c;ES&#xff09;基因编程&#xff08;Genetic Programming&#xff09;Multi-objective Evolutionary Algorithms 遗传算…...

leetcode 637. 二叉树的层平均值

2023.6.29 依旧是层序遍历的变体&#xff0c;在层序遍历的代码中的内层循环求个和&#xff0c;然后出循环之后取个平均值即可实现层平均值&#xff0c;下面上代码&#xff1a; class Solution { public:vector<double> averageOfLevels(TreeNode* root) {vector<doub…...

7-数组创建函数还有哪些?【视频版】

目录 问题视频解答 问题 视频解答 点击观看&#xff1a; 7-数组创建函数还有哪些&#xff1f;...

webrtc源码阅读之P2P流程分析

P2P从宏观原理上其实就是&#xff1a; 收集本地Candidates设置远程Candidates连通性测试及排序 本文我们从Offer端的角度进行源码分析&#xff0c;学习webrtc是如何进行P2P连接的。版本m98。 一、收集本地Candidates examples/peerconnection中&#xff0c;CreateOffer以后&…...

vscode 快速修复(quick fix) 快捷键(Ctrl + .)被占用问题解决方法

vscode 快速修复(quick fix) 快捷键(Ctrl .)被占用 微软拼音的中/英文标点切换的快捷键为Ctrl .&#xff0c;与 vscode 快速修复(quick fix)快捷键冲突。修复方法如下&#xff1a; 切换到微软拼音&#xff0c;在输入法中或英字上&#xff0c;点击右键。 再点设置 - 按键。 …...

阿里云——扩展Linux系统盘

扩展分区和文件系统_Linux系统盘 {#concept_ocb_htw_dhb .concept} 本文提供了如何使用growpart和resize2fs工具完成Linux系统盘分区扩容及文件系统扩展的操作指导。 适用范围 {#section_u9c_3g5_ljs .section} 本文的操作步骤适用于以下分区和文件系统格式的云盘&#xff1…...

TypeScript ~ 掌握基本类型 ②

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; TypeScript ~ TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &…...

【Zookeeper】win安装随笔

目录 下载地址下载目标解压后目录结构配置文件配置文件详情伪分布式安装LinuxZooKeeper audit is disabled启动解决报错&#xff1a;SLF4J: Class path contains multiple SLF4J bindings. _ 下载地址 https://zookeeper.apache.org/releases.html 下载目标 记住选择带bin的…...

Unity 之 最新原生广告Ads接入 -- 助力增长游戏收益

Unity 之 最新Ads原生广告接入流程详解和工具类分享 一&#xff0c;注册 Unity Ads 广告 SDK二&#xff0c;下载 Unity Ads 广告 SDK三&#xff0c;配置 Unity Ads 广告 SDK3.1 广告位展示流程3.2 代码初始化 四&#xff0c;集成 Unity Ads 广告 SDK4.1 相关介绍4.2 代码分享 五…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...