【备战秋招】每日一题: 2023.3.7-百度机试(第一题)-最小化k序列平均值和

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

题目内容

塔子哥是一名数学家,他一直在研究一个关于序列划分的数学问题。他有一个长度为 n n n 的数组,数组中的每个元素都是一个非负整数。他想将这个数组划分成 k k k 个子序列,使得每个子序列中的元素恰好出现一次,且每个子序列都必须非空。他希望将这 k k k 个子序列的平均数之和尽可能地小,这样他就能够更深入地研究这个问题。

为了解决这个问题,塔子哥来到了你的面前,请求你帮助他找到一种最小化平均数之和的划分方案,使得这 k k k 个子序列的平均数之和尽可能小。你能帮帮他吗?

注,子序列可以不连续。例如数组为 [ 3 , 2 , 1 , 3 ] [3,2,1,3] [3,2,1,3] k = 2 k=2 k=2 时,子序列可以拆分为 [ 3 , 1 ] [3,1] [3,1] [ 2 , 3 ] [2,3] [2,3]

输入描述

第一行输入两个正整数 n n n k k k ,代表数组的长度、子序列的数量。

第二行输入 n n n 个正整数 a i a_i ai ,代表数组的元素。 保证序列不含重复元素

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

− 1 0 9 ≤ a i ≤ 1 0 9 -10^9\le a_i \le 10^9 109ai109

输出描述

一个小数,代表最终平均数之和的最小值。保留5位小数

样例

输入

7 3
9 4 5 6 2 1 7

输出

9.20000

k序列平均值和最小

思路:

假设 k = 1 k=1 k=1时,只能分为 1 1 1个。

k = 2 k=2 k=2时,我们要需要分为两个数组,假设原数组为arr,分开后的数组为 a r r 1 arr1 arr1, a r r 2 arr2 arr2,那么我们讨论 a r r 1 arr1 arr1存有几个数最好。

其实只有一个数是最好的,且这个数最小才是最好的,即 a r r 1 arr1 arr1只要一个最小数,其他 n − 1 n-1 n1个数在 a r r 2 arr2 arr2.

证明:

我们对 a r r arr arr进行排序,那么假设 a r r 1 = a r r [ 0 ] arr1=arr[0] arr1=arr[0],所以平均值为和 a r r [ 0 ] + ( s u m − a r r [ 0 ] ) / ( n − 1 ) arr[0]+(sum-arr[0])/(n-1) arr[0]+(sumarr[0])/(n1),此时我们需要证明为何需要一个数,多个数可以吗

我们假设存在一个数 a r r [ i ] arr[i] arr[i],其中 i > 0 i>0 i>0,让这个 a r r [ i ] arr[i] arr[i]并入 a r r 1 arr1 arr1数组,那么平均值和为 ( a r r [ 0 ] + a r r [ i ] ) / 2 + ( s u m − a r r [ 0 ] − a r r [ i ] ) / ( n − 2 ) (arr[0]+arr[i])/2+(sum-arr[0]-arr[i])/(n-2) (arr[0]+arr[i])/2+(sumarr[0]arr[i])/(n2),我们发现平均值由左右两部分组成,左边部分增加了很多,而右边部分减少了一点,所以平均值会增加。当然这只是感性的证明,如果要严格点,需要将平均值的差值进行求解然后证明。

如果只能分一个数字,那么肯定是最小的,这个证明比较简单,假设存在一个树 a r r [ i ] arr[i] arr[i],那么平均值和为 a r r [ i ] + ( s u m − a r r [ i ] ) / ( n − 1 ) arr[i]+(sum-arr[i])/(n-1) arr[i]+(sumarr[i])/(n1),和原始的平均值做个差值即可证明。

Java代码:

import java.util.Arrays;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = sc.nextInt();
        Arrays.sort(a);
        double ans = 0;
        double sum = 0;
        for (int i = 0; i < k - 1; i++)
            ans += a[i];
        for (int i = k - 1; i < n; i++)
            sum += a[i];
        ans = ans + sum / (n - k + 1);
        System.out.println(ans);
    }
}

C++代码

#include <iostream>
#include <algorithm>
using namespace std;
int a[100010];
int main()
{
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++)
        cin>>a[i];
    sort(a,a+n);
    double ans = 0;
    double sum = 0;
    for (int i = 0; i < k - 1; i++)
        ans += a[i];
    for (int i = k - 1; i < n; i++)
        sum += a[i];
    ans = ans + sum / (n - k + 1);
    cout<<ans<<endl;
    return 0;
}

python

line = list(map(lambda x: int(x), input().split()))
n,k = line[0],line[1]

numb = list(map(lambda x: int(x), input().split()))
numb.sort()
sum = 0.0
tt = 0
for i in range(k-1):
    sum += float(numb[i])
for i in range(n-k+1):
    tt += numb[k-1+i]
sum += float(tt/(n-k+1))
print("%.5f" % sum)

js

let line = readline().split(" ").map(Number);
let n = line[0], k = line[1];

let numb = readline().split(" ").map(Number);
numb.sort((a, b) => a - b);
let sum = 0.0;
let tt = 0;
for (let i = 0; i < k - 1; i++) {
  sum += numb[i];
}
for (let i = 0; i <= n - k; i++) {
  tt += numb[k - 1 + i];
}
sum += tt / (n - k + 1);
console.log(sum.toFixed(5));

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值