京东笔试真题 - 失落的宝石(C++/Py/Java /Js/Go)

失落的宝石

京东技术岗 8月8号笔试 第一题

题目内容

一位探险家在古老遗迹中找到了 nnn 个宝箱,每个宝箱里装有 111 到 666 颗宝石。他统计出所有宝箱的宝石总数为 SSS。

随后,探险家决定带走宝石数量最多的 kkk 个宝箱(若出现并列,他可以任选其中的 kkk 个),将剩余的 n−kn-kn−k 个宝箱留给同伴,这些剩余宝箱的宝石总数为 RRR。

现在已知四个整数 n,k,S,Rn,k,S,Rn,k,S,R,请你帮助探险家重构一组可能的原始宝石序列 v1,v2,...,vnv_1,v_2,\dots,v_nv1,v2,...,vn,要求满足:

  • 每个 viv_ivi 均为整数且 1≤vi≤61 \le v_i \le 61≤vi≤6;
  • ∑i=1nvi=S\sum_{i=1}^n v_i = S∑i=1nvi=S;
  • 从中选出 kkk 个最大值(即最大的 kkk 个元素)后,剩下 n−kn-kn−k 个元素的和恰好为 RRR。
    如果不存在符合条件的序列,请指出无解。
    约束条件
  • 宝箱总数 nnn 满足 2≤n≤200 0002 \le n \le 200\,0002≤n≤200000;
  • 取走的宝箱数 kkk 满足 1≤k<n1 \le k < n1≤k<n;
  • 总和 SSS 与剩余和 RRR 满足 1≤R<S≤1.2×1061 \le R < S \le 1.2 \times 10^61≤R<S≤1.2×106。

输入描述

输入只有一行,包含四个整数 nnn, kkk, SSS, RRR,以空格分隔。数据保证满足上述约束范围。

输出描述

若存在合法方案,输出一行 nnn 个整数,表示一组合法的宝箱宝石序列,整数之间用空格分隔;否则输出 -1

样例1

输入

复制代码
5 2 20 10

输出

复制代码
4 4 2 6 4

说明

宝箱总数 n=5n=5n=5,取走 k=2k=2k=2,总宝石数 S=20S=20S=20,剩余宝石数 R=10R=10R=10。剩余宝箱数 m=n−k=3m=n-k=3m=n−k=3,取走的宝石数和 T=S−R=10T=S-R=10T=S−R=10。

枚举阈值 ccc:

  • 当 c=4c=4c=4 时,剩余和 R=10R=10R=10 满足 3≤10≤3×4=123 \le 10 \le 3 \times 4 = 123≤10≤3×4=12,取走和 T=10T=10T=10 满足 2×4=8≤10≤6×2=122 \times 4=8 \le 10 \le 6 \times 2=122×4=8≤10≤6×2=12,因此 c=4c=4c=4 可行。
    构造剩余 333 个宝箱(范围 1,41,41,4):初始每个为 111,剩余调节量 10−3=710-3=710−3=7。依次分配最大值 min⁡(7,3)=3\min(7,3)=3min(7,3)=3,得 4;剩余 444,再分配 min⁡(4,3)=3\min(4,3)=3min(4,3)=3,得 4;最后剩余 111,分配 111 得 2。剩余序列为 4 4 2
    构造取走的 222 个宝箱(范围 4,64,64,6):初始每个为 c=4c=4c=4,和为 888,剩余调节量 10−8=210-8=210−8=2。先分配 min⁡(2,2)=2\min(2,2)=2min(2,2)=2,得 6;再分配 000 得 4。取走序列为 6 4
    合并得到完整序列 4 4 2 6 4。前 222 大的元素为 666 和 444,剩余元素和 4+4+2=104+4+2=104+4+2=10,且总和为 202020,均满足要求。

样例2

输入

复制代码
3 1 10 8

输出

复制代码
-1

说明

宝箱总数 n=3n=3n=3,取走 k=1k=1k=1,总宝石数 S=10S=10S=10,剩余宝石数 R=8R=8R=8。剩余宝箱数 m=2m=2m=2,取走的宝石数和 T=S−R=2T=S-R=2T=S−R=2。

枚举阈值 ccc:

  • 剩余和 R=8R=8R=8 要求 m≤R≤m×cm \le R \le m \times cm≤R≤m×c,即 2≤8≤2c2 \le 8 \le 2c2≤8≤2c,解得 c≥4c \ge 4c≥4。
  • 取走和 T=2T=2T=2 要求 k×c≤T≤6kk \times c \le T \le 6kk×c≤T≤6k,即 c≤2≤6c \le 2 \le 6c≤2≤6,解得 c≤2c \le 2c≤2。
    不存在同时满足 c≥4c \ge 4c≥4 和 c≤2c \le 2c≤2 的整数 ccc,因此无解,输出 -1

样例3

输入

复制代码
5 3 30 12

输出

复制代码
6 6 6 6 6

说明

宝箱总数 n=5n=5n=5,取走 k=3k=3k=3,总宝石数 S=30S=30S=30,剩余宝石数 R=12R=12R=12。剩余宝箱数 m=2m=2m=2,取走的宝石数和 T=18T=18T=18。

枚举阈值 ccc:

  • 当 c=6c=6c=6 时,剩余和满足 2≤12≤2×6=122 \le 12 \le 2 \times 6=122≤12≤2×6=12,取走和满足 3×6=18≤18≤6×3=183 \times 6=18 \le 18 \le 6 \times 3=183×6=18≤18≤6×3=18,边界刚好成立。
    构造剩余 222 个宝箱(范围 1,61,61,6):初始各为 111,剩余调节量 12−2=1012-2=1012−2=10。依次分配 min⁡(10,5)=5\min(10,5)=5min(10,5)=5,得 6,再分配 555,得 6,得到 6 6。取走的 333 个宝箱(范围 6,66,66,6):每个直接为 666,得到 6 6 6
    完整序列为全 6。最大的 333 个均为 666,剩余 222 个的和为 121212,满足边界条件。

样例4

输入

复制代码
4 2 12 5

输出

复制代码
3 2 4 3

说明

宝箱总数 n=4n=4n=4,取走 k=2k=2k=2,总宝石数 S=12S=12S=12,剩余宝石数 R=5R=5R=5。剩余宝箱数 m=2m=2m=2,取走的宝石数和 T=7T=7T=7。

枚举阈值 ccc:

  • c=3c=3c=3 时,剩余和 555 满足 2≤5≤2×3=62 \le 5 \le 2 \times 3=62≤5≤2×3=6,取走和 777 满足 2×3=6≤7≤122 \times 3=6 \le 7 \le 122×3=6≤7≤12,可行。
    剩余 222 个宝箱(范围 1,31,31,3):初始各 111,调节量 5−2=35-2=35−2=3。先分配 min⁡(3,2)=2\min(3,2)=2min(3,2)=2 得 3,再分配 111 得 2,序列为 3 2。取走 222 个宝箱(范围 3,63,63,6):初始各 333 和为 666,调节量 7−6=17-6=17−6=1。第一个分配 111 得 4,第二个得 3,序列为 4 3
    完整序列为 3 2 4 3。最大的 222 个为 444 和 333,剩余和为 3+2=53+2=53+2=5,总和为 121212,符合要求。

题解和思路

思路

实现思路:逻辑分析

  1. 为了让拿走部分宝石最小值尽可能大,必须均匀分配。为了让保留宝石的最大值尽可能少,必须均匀分配。这一步是保证拿走的最小值必须大于等于保留最大值
  2. 判断是否能构成包含以下方面:
    • 是否存在宝箱宝石数量为0
    • 是否存在平均分配后,宝石数量大于6
    • 是否均匀分配后,拿走宝箱最小宝石数量小于留下宝箱最大宝石数量
  3. 接下来就比较简单了,先分配拿走宝箱再分配留下宝箱,两种都可通过取余得出超过各自平均值的数量,给指定数量分配平均值 + 1的数量即可。
  4. 算法整体时间复杂度为O(n)

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n,k,S,R;
    cin >> n >> k >> S >> R;
    // 剩余数量
    int T = (n - k);
    // 基本数量不满足每个宝箱至少 1 颗
    if (S - R < k || R < T) {
        cout << -1 << endl;
        return 0;
    }
    

    int takeAverage = (S - R) / k;
    int exceedAverageCount = (S - R) % k;
    // 向上取整
    int remaingUpAverage = (R + T - 1) / T;
    int remaingAverage = R / T;
    // 无法满足分配  拿走最小值小于留下最大值  同时检验上边界是否满足 <=6
    if (takeAverage < remaingUpAverage || (takeAverage + (exceedAverageCount > 0 ? 1 : 0)) > 6 ||  remaingUpAverage > 6 ) {
        cout << -1 << endl;
        return 0;
    }
    
    // 构建结果
    vector<int> ans(n);
    
    
    // 先处理被带走的
    for (int i = 0; i < k; i++) {
        ans[i] = takeAverage;
        if (exceedAverageCount > 0) {
            ans[i]++;
            exceedAverageCount--;
        }
    }
    // 处理剩余
    
    
    int exceedTakeAverageCount = R % T;
    for (int i = k; i < n; i++) {
        ans[i] = remaingAverage;
        if (exceedTakeAverageCount > 0) {
            ans[i]++;
            exceedTakeAverageCount--;
        } 
    }
    // 输出结果
    for (int i = 0; i < n; i++) {
        if (i > 0) {
            cout << " ";
        }
        cout << ans[i];
    }
    return 0;
}

Java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());
        int S = Integer.parseInt(st.nextToken());
        int R = Integer.parseInt(st.nextToken());

        // 剩余数量
        int T = n - k;

        // 基本数量不满足每个宝箱至少 1 颗
        if (S - R < k || R < T) {
            System.out.println(-1);
            return;
        }

        int takeAverage = (S - R) / k;
        int exceedAverageCount = (S - R) % k;

        // 向上取整
        int remaingUpAverage = (R + T - 1) / T;
        int remaingAverage = R / T;

        // 无法满足分配
        // 拿走最小值小于留下最大值
        // 同时检验上边界是否满足 <=6
        if (takeAverage < remaingUpAverage ||
            takeAverage + (exceedAverageCount > 0 ? 1 : 0) > 6 ||
            remaingUpAverage > 6) {
            System.out.println(-1);
            return;
        }

        // 构建结果
        int[] ans = new int[n];

        // 先处理被带走的
        for (int i = 0; i < k; i++) {
            ans[i] = takeAverage;
            if (exceedAverageCount > 0) {
                ans[i]++;
                exceedAverageCount--;
            }
        }

        // 处理剩余
        int exceedTakeAverageCount = R % T;
        for (int i = k; i < n; i++) {
            ans[i] = remaingAverage;
            if (exceedTakeAverageCount > 0) {
                ans[i]++;
                exceedTakeAverageCount--;
            }
        }

        // 输出结果
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            if (i > 0) {
                sb.append(" ");
            }
            sb.append(ans[i]);
        }
        System.out.println(sb);
    }
}

python

python 复制代码
n, k, S, R = map(int, input().split())

# 剩余数量
T = n - k

# 基本数量不满足每个宝箱至少 1 颗
if S - R < k or R < T:
    print(-1)
    exit()

takeAverage = (S - R) // k
exceedAverageCount = (S - R) % k

# 向上取整
remaingUpAverage = (R + T - 1) // T
remaingAverage = R // T

# 无法满足分配
# 拿走最小值小于留下最大值
# 同时检验上边界是否满足 <=6
if (takeAverage < remaingUpAverage or
    takeAverage + (1 if exceedAverageCount > 0 else 0) > 6 or
    remaingUpAverage > 6):
    print(-1)
    exit()

# 构建结果
ans = [0] * n

# 先处理被带走的
for i in range(k):
    ans[i] = takeAverage
    if exceedAverageCount > 0:
        ans[i] += 1
        exceedAverageCount -= 1

# 处理剩余
exceedTakeAverageCount = R % T
for i in range(k, n):
    ans[i] = remaingAverage
    if exceedTakeAverageCount > 0:
        ans[i] += 1
        exceedTakeAverageCount -= 1

# 输出结果
print(" ".join(map(str, ans)))

Javascript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.on("line", (line) => {
    const [n, k, S, R] = line.trim().split(/\s+/).map(Number);

    // 剩余数量
    const T = n - k;

    // 基本数量不满足每个宝箱至少 1 颗
    if (S - R < k || R < T) {
        console.log(-1);
        rl.close();
        return;
    }

    const takeAverage = Math.floor((S - R) / k);
    let exceedAverageCount = (S - R) % k;

    // 向上取整
    const remaingUpAverage = Math.floor((R + T - 1) / T);
    const remaingAverage = Math.floor(R / T);

    // 无法满足分配
    // 拿走最小值小于留下最大值
    // 同时检验上边界是否满足 <=6
    if (takeAverage < remaingUpAverage ||
        takeAverage + (exceedAverageCount > 0 ? 1 : 0) > 6 ||
        remaingUpAverage > 6) {
        console.log(-1);
        rl.close();
        return;
    }

    // 构建结果
    const ans = new Array(n).fill(0);

    // 先处理被带走的
    for (let i = 0; i < k; i++) {
        ans[i] = takeAverage;
        if (exceedAverageCount > 0) {
            ans[i]++;
            exceedAverageCount--;
        }
    }

    // 处理剩余
    let exceedTakeAverageCount = R % T;
    for (let i = k; i < n; i++) {
        ans[i] = remaingAverage;
        if (exceedTakeAverageCount > 0) {
            ans[i]++;
            exceedTakeAverageCount--;
        }
    }

    // 输出结果
    console.log(ans.join(" "));
    rl.close();
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var n, k, S, R int
	fmt.Fscan(in, &n, &k, &S, &R)

	// 剩余数量
	T := n - k

	// 基本数量不满足每个宝箱至少 1 颗
	if S-R < k || R < T {
		fmt.Fprintln(out, -1)
		return
	}

	takeAverage := (S - R) / k
	exceedAverageCount := (S - R) % k

	// 向上取整
	remaingUpAverage := (R + T - 1) / T
	remaingAverage := R / T

	// 无法满足分配
	// 拿走最小值小于留下最大值
	// 同时检验上边界是否满足 <=6
	if takeAverage < remaingUpAverage ||
		takeAverage+(func() int {
			if exceedAverageCount > 0 {
				return 1
			}
			return 0
		}()) > 6 ||
		remaingUpAverage > 6 {
		fmt.Fprintln(out, -1)
		return
	}

	// 构建结果
	ans := make([]int, n)

	// 先处理被带走的
	for i := 0; i < k; i++ {
		ans[i] = takeAverage
		if exceedAverageCount > 0 {
			ans[i]++
			exceedAverageCount--
		}
	}

	// 处理剩余
	exceedTakeAverageCount := R % T
	for i := k; i < n; i++ {
		ans[i] = remaingAverage
		if exceedTakeAverageCount > 0 {
			ans[i]++
			exceedTakeAverageCount--
		}
	}

	// 输出结果
	for i := 0; i < n; i++ {
		if i > 0 {
			fmt.Fprint(out, " ")
		}
		fmt.Fprint(out, ans[i])
	}
}
相关推荐
电商API_180079052472 天前
京东商品详情API技术解析:数据结构、调用实践与系统集成方案
python·api·跨境电商·京东·商品详情
加油20195 个月前
京东人事管理8项规定
管理·京东·8项规定
Cyril_KI2 年前
京东 2025届秋招 自然语言处理
自然语言处理·京东·面试经验·2025届校招
亿牛云爬虫专家2 年前
CSV文件自动化生成:用Pandas与Datetime高效处理商品信息
运维·pandas·爬虫代理·电商·代理ip·datetime·京东
27669582922 年前
京东e卡滑块 分析
java·javascript·python·node.js·go·滑块·京东
junjie xu2 年前
内推|京东|后端开发|运维|算法...|北京 更多岗位扫内推码了解,直接投递,跟踪进度
京东云·内推·京东
志远19972 年前
笔试算法-编程练习-01-J-24
数据结构·python·算法·京东·大厂笔试
Luca_kill2 年前
Python爬虫实战之爬取京东商品数据
爬虫·python·京东
假正经的小柴2 年前
【开源设计】京东慢SQL组件:sql-analysis
java·数据库·sql·京东