【备战秋招】每日一题:2023.3.15-阿里OD机试(第三题)-k次操作最小化极差

news/2024/10/17 16:22:29/

在线评测链接:P1084

题目内容

在一个遥远的王国里,有一座高耸入云的宝塔,据说里面藏有神秘的宝藏。但是,进入宝塔的道路异常困难,需要经过各种险阻,其中一个重要的关卡是“平衡之门”。

平衡之门是一条走廊,两边是无数个数码显示屏幕,每个屏幕上都显示着一个整数。在走廊中央有一个控制台,上面有两个按钮,一个是“乘2”按钮,一个是“除以 2 2 2”按钮。每次按下其中一个按钮,控制台上的数字就会相应地变化。走廊中的每个数字最多只能被操作一次。

王国的宝藏猎人们想要通过平衡之门,以最小的代价进入宝塔。他们发现,只需要选择恰好 k k k 个数字,使得每个数字经过不超过一次的操作后,可以得到所有的数字,就可以顺利通过平衡之门。现在他们需要你的帮助,计算出最小的极差,即经过操作后最大值和最小值之差的最小值。

输入描述

第一行输入两个正整数 n n n k k k ,代表数组长度以及选择的元素数量。

第二行输入 n n n个元素,代表给定的数组。

1 ≤ k ≤ n ≤ 1 0 5 1 \leq k \leq n \leq 10^5 1kn105

1 ≤ a i ≤ 1 0 9 1 \leq a_i \leq 10^9 1ai109

输出描述

k k k 次操作后,数组极差的最小值。

样例

输入输出示例仅供调试,后台判题数据一般不包含示例

输入

4 2
1 4 3 5

输出

2

样例

输入

6 1
9 4 3 4 2 5

输出

3

思路

贪心

1.观察到每个数最多修改一次,那么显然最优的修改方案一定是前 i i i小都乘以 2 2 2,前 k − i k-i ki大都除以 2 2 2

2.那么排序,枚举 i i i然后模拟这个过程,去求最大值最小值,复杂度达到 O ( n 2 ) O(n^2) O(n2) 。但好在我们只关心极差,即最大值和最小值,所以不需要去模拟操作每一个数。而是考虑一次操作后结果会分成三段,分别去求这三段的最值就好了。如下图所示,我们只需要从这六个红圈中取极值即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VdvFIyQ5-1687342006273)(/mt/P1084/img1.png)]

类似题目推荐

推荐几道贪心题~

LeetCode

LeetCode上的贪心题,代码随想录总结的非常好了,见 贪心 - 代码随想录

CodeFun2000

P1075 拼多多-2023.3.12-飞机大战

P1176 2023.04.08-华为od-第三题-最多等和不相交连续子序列

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

P1070 2023.3.7-百度-第一题-最小化k序列平均值和

代码

CPP

#include <bits/stdc++.h>
using namespace std;int in() {int x;cin >> x;return x;
}
int main()
{int n = in(), k = in();int a[n];for (int i = 0; i < n; i++) {a[i] = in();}sort(a, a+n);           //排序int ans = (int)1e9;for (int i = 0; i <= k; i++) {      //枚举修改前i小//三者不一定都存在,所以最小值初始化为一个较大的值,最大值初始化为一个小的值,再用三者更新int mi = (int)1e9, mx = 0;      if(i > 0) {     // 第一段的端点mi = min(mi, a[0]*2);mx = max(mx, a[i-1]*2);}if(k-i > 0) {   // 第三段的端点mi = min(mi, a[n-(k-i)]/2);mx = max(mx, a[n-1]/2);}if(n != k) {    // 第二段的端点mi = min(mi, a[i]);mx = max(mx, a[n-(k-i)-1]);}ans = min(ans, mx - mi);        //更新极差最小值}cout << ans << endl;
}

python

n, k = map(int, input().split())
a = list(map(int, input().split()))
a.sort()  # 排序
ans = float("inf")
for i in range(k + 1):  # 枚举修改前i小# 三者不一定都存在,所以最小值初始化为一个较大的值,最大值初始化为一个小的值,再用三者更新mi, mx = float("inf"), 0if i > 0:  # 第一段的端点mi = min(mi, a[0] * 2)mx = max(mx, a[i - 1] * 2)if k - i > 0:  # 第三段的端点mi = min(mi, a[n - (k - i)] // 2)mx = max(mx, a[n - 1] // 2)if n != k:  # 第二段的端点mi = min(mi, a[i])mx = max(mx, a[n - (k - i) - 1])ans = min(ans, mx - mi)  # 更新极差最小值
print(ans)

Java

import java.util.*;
class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt(), k = in.nextInt();int[] a = new int[n];for (int i = 0; i < n; i++) {a[i] = in.nextInt();}Arrays.sort(a);			//排序int ans = (int)1e9;for (int i = 0; i <= k; i++) {		int mi = (int)1e9, mx = 0;		// 第一段的端点if(i > 0) {		mi = Math.min(mi, a[0]*2);mx = Math.max(mx, a[i-1]*2);}// 第三段的端点if(k-i > 0) {	mi = Math.min(mi, a[n-(k-i)]/2);mx = Math.max(mx, a[n-1]/2);}// 第二段的端点if(n != k) {	mi = Math.min(mi, a[i]);mx = Math.max(mx, a[n-(k-i)-1]);}// 更新最小极差ans = Math.min(ans, mx - mi);		}System.out.println(ans);}
}

Go

package mainimport ("fmt""sort"
)func main() {var n, k intfmt.Scan(&n, &k)// 读入序列并排序a := make([]int, n)for i := 0; i < n; i++ {fmt.Scan(&a[i])}sort.Ints(a)// 初始化最小极差为一个较大的值ans := int(1e9)// 枚举修改前i小的数for i := 0; i <= k; i++ {// 初始化三个段的端点的最小值和最大值mi, mx := int(1e9), 0// 第一段的端点if i > 0 {mi = min(mi, a[0]*2)mx = max(mx, a[i-1]*2)}// 第三段的端点if k-i > 0 {mi = min(mi, a[n-(k-i)]/2)mx = max(mx, a[n-1]/2)}// 第二段的端点if n != k {mi = min(mi, a[i])mx = max(mx, a[n-(k-i)-1])}// 更新最小极差ans = min(ans, mx-mi)}// 输出最小极差fmt.Println(ans)
}// 取两个整数的最小值
func min(a, b int) int {if a < b {return a}return b
}// 取两个整数的最大值
func max(a, b int) int {if a > b {return a}return b
}

Js

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');const nk = lines[0].trim().split(' ').map(Number);const n = nk[0], k = nk[1];const a = lines[1].trim().split(' ').map(Number);a.sort((a , b) => {return a - b;});  // 排序let ans = 1e9;for (let i = 0; i <= k; i++) {  // 枚举修改前i小// 三者不一定都存在,所以最小值初始化为一个较大的值,最大值初始化为一个小的值,再用三者更新let mi = 1e9, mx = 0;if (i > 0) {  // 第一段的端点mi = Math.min(mi, a[0] * 2);mx = Math.max(mx, a[i - 1] * 2);}if (k - i > 0) {  // 第三段的端点mi = Math.min(mi, a[n - (k - i)] >> 1);mx = Math.max(mx, a[n - 1] >> 1);}if (n !== k) {  // 第二段的端点mi = Math.min(mi, a[i]);mx = Math.max(mx, a[n - (k - i) - 1]);}ans = Math.min(ans, mx - mi);  // 更新极差最小值}console.log(ans);
});

http://www.ppmy.cn/news/533373.html

相关文章

Linux组管理和权限管理

一、Linux组 在linux中每个用户必须属于一个组&#xff0c;不能独立于组外&#xff0c;在linux中 文件所有者 一般为文件创建者&#xff0c;可以通过ls -ahl 查看文件所有者 chown 用户名 文件名 &#xff1a;修改文件所有者 groupadd 组名 创建组 当某个用户创建了一个文件…

【C++学习】C++入门 | 缺省参数 | 函数重载 | 探究C++为什么能够支持函数重载

写在前面&#xff1a; 上一篇文章我介绍了C该怎么学&#xff0c;什么是命名空间&#xff0c;以及C的输入输出&#xff0c; 这里是传送门&#xff1a;http://t.csdn.cn/Oi6V8 这篇文章我们继续来学习C的基础知识。 目录 写在前面&#xff1a; 1. 缺省参数 2. 函数重载 3…

HD90假钞辨真伪

网友现在是一股强大的力量。提醒大家看好手中的人民币哦

银行取票机

import array.SuperArray;public class queue {private SuperArray superArray new SuperArray();// 入队public void add(int data) {superArray.addToTail(data);}// 出队public int pop() {Integer select superArray.select(0);superArray.delete(0);return select;}publ…

人民币(纸币)检测

其实原理很简单&#xff0c;就是利用不同面额的纸币&#xff0c;其大小不一样来检测的&#xff08;也可以根据纸币颜色的不同来识别&#xff0c;有兴趣的可以试试&#xff09;&#xff0c;这里二值化灰度图的阈值就是通过上篇的OSTU自适应阈值算法获得的阈值&#xff0c;效果非…

假硬币称重

解题思路&#xff1a; 因为题目的编辑中已经是知道了最终结果的&#xff0c;所以&#xff0c;可以倒过来思考&#xff0c;通过知晓的结果来判断相对应的过程是否符合对应的猜想&#xff0c;简单来说就是&#xff0c;自己称重硬币的过程&#xff0c;是不是就是出题者的意图&…

点钞机语音怎么打开_弱弱问一下验钞机怎么开声音

A&#xff1a;阀门磁性锁是一种阀门磁性锁&#xff0c;阀盖、阀杆、阀盖帽和手柄组成。阀盖帽和阀杆上有连接装置&#xff0c;阀盖帽上设有钢销槽&#xff0c;底部放有磁铁&#xff0c;磁铁套于弹簧内&#xff0c;钢销置于弹簧之上&#xff0c;阀盖上设有凹槽&#xff0c;手柄为…

你知道怎样用Excel打印【条形码】吗?

Excel功能超出你的想象&#xff0c;不仅可以处理大量的数据、制作图表等等&#xff0c;其实在Excel中也可以轻松打印各种条形码&#xff0c;而且设置非常简单&#xff0c;下面我们来看看如何用Excel来打印【条形码】&#xff1f; **Step1&#xff1a;**在Excel选项中将【开发工…