【笔试刷题】小米-2026.03.14-第二套-改编真题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线200+套真题改编解析,后续会持续更新的
春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗
小米-2026.03.14-第二套
小米-2026.03.14-第二套
这套题的梯度很顺。第一题是实现型热身,关键在于把比较规则一层不漏地写对;第二题才是真正的分水岭,必须先把错误题意修正成和样例一致的版本,再去做区间 DP;第三题则是经典贪心模型,能不能一眼认出“截止日排序 + 最小堆”基本决定了写题速度。
题目一:定制选品单
题面看起来只是重新排商品顺序,但真正的排序键不是固定的,而是顾客临时给出的一组维度优先级。因为 很小,直接按顾客顺序做多关键字比较就够了,别把矩阵读反就行。
难度:简单
题目二:并炉品阶
这题最麻烦的不是实现,而是原始题面规则和样例互相矛盾。正式版必须按样例修正成“若 则合成后是
,否则是
”,之后用区间 DP 维护每一段能炼出的所有品阶。
难度:中等
题目三:奖章作业表
本质是单位时长任务选择问题。把作业按截止日排序,堆里始终只保留当前能按时做完的最高收益集合;一旦数量超过当前截止日,就删掉收益最小的那份作业。
难度:中等
定制选品单
问题描述
小基 正在为一位顾客整理门店首页的推荐顺序。
店里共有 件商品,每件商品都有
个评价维度。顾客不会直接给出一个总分,而是会给出一个长度为
的排列
,表示他看重这些维度的先后顺序。
比较两件商品时,规则如下:
- 先比较它们在维度
上的分数,分数更高的排在前面。
- 如果这一维相同,就继续比较维度
。
- 按同样方式一路比较到维度
。
已知任意两件商品在全部 个维度上的分数不会完全一样。请输出按顾客偏好从高到低排好序后的商品编号。
输入格式
第一行输入两个整数 ,表示商品数量和评价维度数量。
第二行输入 个整数
,它们是
的一个排列,表示顾客给出的维度优先级。
接下来输入一个 的分数矩阵。
- 第
行第
列的整数
,表示商品
在第
个维度上的分数。
输出格式
输出一行 个整数,表示按顾客偏好从高到低排序后的商品编号。
样例输入
5 3
1 3 2
4 4 3 4 3
5 2 4 4 4
3 5 2 3 3
样例输出
2 1 4 5 3
样例说明
| 样例 | 解释说明 |
|---|---|
| 样例 1 | 顾客先看第 2 1 4 5 3。 |
数据范围
是
的一个排列
- 保证不存在两件商品在全部维度上的分数完全相同
题解
这题没有隐藏做法,本质就是把“顾客给出的维度顺序”变成真正的排序键。
每件商品都对应一个长度为 的分数向量,但比较时不能按维度编号
直接看,而是必须严格按照顾客给出的顺序
去逐项比较。
因为 ,一次比较最多只会看
个维度,所以直接排序就足够了:
- 先读入顾客给出的维度顺序。
- 再读入分数矩阵,保留“第几维、哪件商品”的分数。
- 排序时枚举顾客给出的维度顺序,找到第一处不同分数,分高的商品排前面。
题目保证不存在两个商品在全部维度上完全相同,所以比较过程一定能在某一维分出先后。
时间复杂度是 。这里的
很小,可以直接看成常数;空间复杂度是
,用于存储分数矩阵。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def solve() -> None:
n, k = map(int, input().split())
ords = [int(x) - 1 for x in input().split()]
sc = [list(map(int, input().split())) for _ in range(k)]
ids = list(range(n))
def key(i: int):
# 直接把顾客关心的分数顺序拼成排序键。
return tuple(-sc[d][i] for d in ords)
ids.sort(key=key)
print(*[i + 1 for i in ids])
if __name__ == "__main__":
solve()
- Cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector<int> ord(k);
for (int i = 0; i < k; ++i) {
cin >> ord[i];
--ord[i];
}
vector<vector<int>> sc(k, vector<int>(n));
for (int i = 0; i < k; ++i) {
for (int j = 0; j < n; ++j) {
cin >> sc[i][j];
}
}
vector<int> ids(n);
iota(ids.begin(), ids.end(), 0);
sort(ids.begin(), ids.end(), [&](int x, int y) {
// 按顾客给出的维度顺序依次比较。
for (int d : ord) {
if (sc[d][x] != sc[d][y]) {
return sc[d][x] > sc[d][y];
}
}
return x < y;
});
for (int i = 0; i < n; ++i) {
if (i) {
cout << ' ';
}
cout << ids[i] + 1;
}
cout << '\n';
return 0;
}
- Java
import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.Arrays;
public class Main {
static class FastScanner {
private final BufferedInputStream in = new BufferedInputStream(System.in);
private final byte[] buf = new byte[1 << 16];
private int len = 0;
private int ptr = 0;
private int read() throws IOException {
if (ptr >= len) {
len = in.read(buf);
ptr = 0;
if (len <= 0) {
return -1;
}
}
return buf[ptr++];
}
int nextInt() throws IOException {
int c;
do {
c = read();
} while (c <= 32 && c != -1);
int sign = 1;
if (c == '-') {
sign = -1;
c = read();
}
int val = 0;
while (c > 32) {
val = val * 10 + c - '0';
c = read();
}
return val * sign;
}
}
public static void main(String[] args) throws Exception {
FastScanner fs = new FastScanner();
int n = fs.nextInt();
int k = fs.nextInt();
int[] ord = new int[k];
for (int i = 0; i < k; i++) {
ord[i] = fs.nextInt() - 1;
}
int[][] sc = new int[k][n];
for (int i = 0; i < k; i++) {
for (int j = 0; j < n; j++) {
sc[i][j] = fs.nextInt();
}
}
Integer[] ids = new Integer[n];
for (int i = 0; i < n; i++) {
ids[i] = i;
}
Arrays.sort(ids, (x, y) -> {
// 按顾客给出的维度优先级逐项比较。
for (int d : ord) {
if (sc[d][x] != sc[d][y]) {
return Integer.compare(sc[d][y], sc[d][x]);
}
}
return Integer.compare(x, y);
});
StringBuilder out = new StringBuilder();
for (int i = 0; i < n; i++) {
if (i > 0) {
out.append(' ');
}
out.append(ids[i] + 1);
}
out.append('\n');
System.out.print(out);
}
}
并炉品阶
问题描述
小柯正在整理一排待入炉的药胚。第 枚药胚的当前品阶是
。
每次操作只能选择两个相邻药胚合并。设它们当前品阶分别为 和
,那么新药胚的品阶按下面的正式规则计算:
- 如果
,合并结果是
。
- 否则,合并结果是
。
合并后,新药胚会留在原来的位置,整排药胚长度减一。不断操作,直到整排只剩下一枚药胚为止。
请计算:
- 最终药胚可能达到的最高品阶。
- 最终药胚可能出现的不同品阶数量。
输入格式
第一行输入两个正整数 。
第二行输入 个正整数
,表示初始药胚的品阶。
输出格式
输出一行两个整数,分别表示:
- 最终药胚可能达到的最高品阶。
- 最终药胚可能出现的不同品阶数量。
样例输入
6 2
2 1 5 1 1 2
样例输出
7 3
样例说明
| 样例 | 解释说明 |
|---|---|
| 样例 1 | 合并顺序不同,最终品阶会不同。按某种顺序可以做到最高品阶 7 3。 |
数据范围
题解
这题最重要的一步,是把正式规则固定成题面现在这版:
- 若
,结果是
。
- 否则结果是
。
一旦规则确定,问题就变成了“这一段药胚最后能炼出哪些品阶”。
设 can[l][r] 表示区间 最终可能得到的所有品阶集合。
1. 状态定义
当区间里只有一枚药胚时,答案只有它自己:
can[i][i] = {a_i}。
2. 为什么可以做区间 DP
区间 的最后一次合并,一定是把它拆成两段:
- 左边是
- 右边是
左段先独立合成一枚药胚,右段也独立合成一枚药胚,最后再把这两枚合在一起。
所以只要枚举最后一次合并的位置 ,再把
can[l][m] 和 can[m+1][r] 里的所有可能值按规则合并,就能得到 can[l][r]。
3. 朴素转移为什么还不够
如果直接枚举左值 、右值
,一次转移会是
,其中
是可能的品阶范围。
这里初始品阶不超过 ,每次合并最多加
,所以最终品阶不会超过
。也就是说
。
虽然范围不大,但总共有很多个区间和拆分点,直接四重枚举还是显得笨。
4. 把一次集合合并降到 &preview=true)
固定较大的那个值为 。
如果想让结果还是 ,说明较小值必须满足:
因为这时差值严格大于 ,结果不会升阶。
如果想让结果变成 ,说明较小值必须落在:
因为这时差值不超过 ,会升一阶。
于是对左右两个集合各做一遍前缀计数,就能在 时间判断:
- 另一边是否存在一个值落在
- 另一边是否存在一个值落在
这样一次“两个集合的合并”就能压到 。
5. 复杂度
区间 DP 一共有 个“区间 + 拆分点”组合。
每次集合合并是 ,而
。
所以总时间复杂度是 ,在这题的数据范围里完全可行;空间复杂度是
。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def upd(dst, left, right, k, mx):
# 前缀计数用于判断“某个范围内是否存在可行值”。
pl = [0] * (mx + 1)
pr = [0] * (mx + 1)
for v in range(1, mx + 1):
pl[v] = pl[v - 1] + left[v]
pr[v] = pr[v - 1] + right[v]
for v in range(1, mx + 1):
if left[v]:
lo = max(1, v - k)
# 若右边有值落在 [v-k, v],则能升到 v+1。
if v + 1 <= mx and pr[v] - pr[lo - 1] > 0:
dst[v + 1] = 1
# 若右边有值 <= v-k-1,则结果保持在 v。
hi = v - k - 1
if hi >= 1 and pr[hi] > 0:
dst[v] = 1
if right[v]:
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力
查看16道真题和解析