【笔试刷题】2026.03.21-小米-改编真题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线200+套真题改编解析,后续会持续更新的
春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗
2026.03.21-小米
这套两题区分度很清楚。第一题是经典的“把绝对值和转成符号枚举”,关键在于能不能第一时间想到只需要检查 种符号组合;第二题难点明显更高,需要把“交换 + 删除”重新理解成带保留位数的高精度 DP,题意不转过来就很难下手。
第一题是标准贪心枚举题。虽然原题包装成装备属性,但本质就是从三维向量里选出 个点,让三个维度和的绝对值之和最大。第二题更像笔试压轴,表面是数字操作,实质上考的是“首位决定符号、后缀只负责补偿”的性质,建模清楚以后才能把状态压到
。
01. 装备选配
问题描述
小基 正在准备挑战一个高难度副本。仓库里一共有 件候选装备,第
件装备会对角色的三项属性产生影响:
- 力量变化为
- 敏捷变化为
- 智力变化为
这些数值可以是正数,也可以是负数。
现在她必须从中恰好挑出 件装备同时穿戴。设最终三项属性变化分别为:
她把这套装备的综合评分定义为:
请你求出,最多能把这个综合评分提高到多少。
输入格式
第一行输入两个整数 ,表示候选装备数量和需要挑选的装备数量。
接下来 行,每行输入三个整数
,表示第
件装备对三项属性的变化值。
输出格式
输出一行一个整数,表示最大可能的综合评分。
样例输入
5 3
1 -2 3
-4 5 -6
7 -8 -9
-10 11 -12
13 -14 15
样例输出
54
样例说明
选择第 件装备时,三项属性和分别为:
因此综合评分为:
数据范围
题解
这题的关键在于先把目标值拆成若干个线性表达式,再从中取最大值,这样绝对值就被处理掉了。
核心转化
对于任意一组最终和 ,总能找到一组符号
,其中每个符号都是
或
,使得:
原因很直接:
- 如果
,就取
- 如果
,就取
另外两个维度同理。
所以最终答案,一定等于某一组符号下的:
最大值。
固定符号以后怎么做
固定一组符号 后,第
件装备的贡献就变成:
如果选中了若干件装备,那么对应总评分就是这些 的和。
于是问题退化成:
- 从
个数里选出恰好
个
- 让它们的和最大
最优策略显然是把所有 排序,取最大的
个。
为什么只要枚举
种情况
三个维度,每个维度的符号只有 或
两种选择,所以一共只有:
种组合。
把这 种组合全部算一遍,每种组合都取一次最大的
个贡献,最后取最大值就是全局最优答案。
复杂度分析
一共枚举 种符号组合,每次需要排序一次:
- 时间复杂度:
- 空间复杂度:
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def solve() -> None:
n, m = map(int, input().split())
items = [tuple(map(int, input().split())) for _ in range(n)]
ans = -10**30
# 三个维度各有正负两种符号,一共 8 种组合。
for sx in (-1, 1):
for sy in (-1, 1):
for sz in (-1, 1):
vals = []
for x, y, z in items:
vals.append(sx * x + sy * y + sz * z)
vals.sort(reverse=True)
cur = sum(vals[:m])
if cur > ans:
ans = cur
print(ans)
if __name__ == "__main__":
solve()
- Cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<long long, 3>> items(n);
for (int i = 0; i < n; ++i) {
cin >> items[i][0] >> items[i][1] >> items[i][2];
}
long long ans = LLONG_MIN;
for (int sx : {-1, 1}) {
for (int sy : {-1, 1}) {
for (int sz : {-1, 1}) {
vector<long long> vals;
vals.reserve(n);
for (const auto& item : items) {
// 固定符号后,每件装备会变成一个一维贡献值。
vals.push_back(
1LL * sx * item[0] +
1LL * sy * item[1] +
1LL * sz * item[2]
);
}
sort(vals.begin(), vals.end(), greater<long long>());
long long cur = 0;
for (int i = 0; i < m; ++i) {
cur += vals[i];
}
ans = max(ans, cur);
}
}
}
cout << ans << '\n';
return 0;
}
- Java
import java.io.*;
import java.util.*;
public class Main {
static class FastScanner {
private final InputStream in = System.in;
private final byte[] buffer = new byte[1 << 16];
private int ptr = 0;
private int len = 0;
private int read() throws IOException {
if (ptr >= len) {
len = in.read(buffer);
ptr = 0;
if (len <= 0) {
return -1;
}
}
return buffer[ptr++];
}
long nextLong() throws IOException {
int c;
do {
c = read();
} while (c <= 32 && c != -1);
int sign = 1;
if (c == '-') {
sign = -1;
c = read();
}
long 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 = (int) fs.nextLong();
int m = (int) fs.nextLong();
long[][] items = new long[n][3];
for (int i = 0; i < n; i++) {
items[i][0] = fs.nextLong();
items[i][1] = fs.nextLong();
items[i][2] = fs.nextLong();
}
long ans = Long.MIN_VALUE;
int[] signs = {-1, 1};
for (int sx : signs) {
for (int sy : signs) {
for (int sz : signs) {
Long[] vals = new Long[n];
for (int i = 0; i < n; i++) {
vals[i] = sx * items[i][0] + sy * items[i][1] + sz * items[i][2];
}
Arrays.sort(vals, Collections.reverseOrder());
long cur = 0;
for (int i = 0; i < m; i++) {
cur += vals[i];
}
ans = Math.max(ans, cur);
}
}
}
System.out.println(ans);
}
}
02. 最小数差
问题描述
K 小姐拿到了两个都是 位的十进制数
和
。已知在每一个对应数位上,这两个数的数字都不相同。
她可以进行两类操作:
- 交换操作:选择某一位,把
和
在这一位上的数字互换。
- 删除操作:选择某一位,把两个数在这一位上的数字同时删除,然后把剩余数字按原顺序重新拼接。
补充限制如下:
- 删除后允许出现前导零。
- 最低位不能删除。
- 删除操作最多执行
次。
- 交换操作可以执行任意次。
请你求出,在最多删除 位的前提下,两个数差的绝对值最小可以是多少。
输入格式
第一行输入两个整数 。
第二行输入十进制数 。
第三行输入十进制数 。
保证:
和
都恰好是
位数;
- 对任意位置
,都有
。
输出格式
输出一个整数,表示最小可能的绝对差值。
样例输入
6 2
329304
878189
样例输出
715
样例说明
一种最优做法是:
- 删除第
位和第
位;
- 再对部分保留位执行交换。
处理后可以得到两个新数,它们的绝对差最小为 。
数据范围
题解
这题表面上有交换和删除两种操作,真正需要追踪的信息只有每一位上两个数字形成的差值。
第一步:把交换操作重新理解
设第 位上两个数字分别是
和
,并且
。
无论这一位交换还是不交换,保留下来以后对两个数差值的贡献只可能是:
因此真正有用的信息只有:
这题就变成了:
- 从前
位里最多删掉
位;
- 最后一位必须保留;
- 对于每个保留下来的位置,可以把它当成一个十进制位上的
或
;
- 要让最终形成的高精度整数最接近
。
第二步:为什么只需要维护四种极值
假设当前结果一共保留 位,那么当前这一位如果被保留,它就是最高位,权重为:
而所有后缀位的绝对值总和严格小于这个权重。
所以最高位的正负,会直接决定整个数的大方向:
- 想让结果尽量大,最高位一定取正;
- 想让结果尽量小,最高位一定取负;
- 想得到最小正数,最高位取正后,后缀一定要尽量小;
- 想得到最大负数,最高位取负后,后缀一定要尽量大。
因此对每个保留位数 ,只需要维护:
maxVal[t]:恰好保留位时能得到的最大值
minVal[t]:恰好保留位时能得到的最小值
bestPos[t]:恰好保留位时最小的正数
bestNeg[t]:恰好保留位时最大的负数
第三步:从后往前做 DP
最后一位不能删除,所以 DP 的起点就是最后一位自己:
- 保留
位时,最大值、最小正数都是
- 最小值、最大负数都是
然后从后往前转移。
假设当前处理到第 位,并且最终一共保留
位。
如果保留这一位,它会成为当前结果的最高位,贡献是:
再拼接上后缀保留 位的结果。
如果删除这一位,就直接继承后缀保留 位的状态。
于是可以分别更新这四类极值。
为什么答案一定在这些状态里
对于任意一个合法结果:
- 要么它是正数,那么它对应某个保留位数下的一个正值,最优答案一定不会比
bestPos更小; - 要么它是负数,那么它的绝对值至少不会比
-bestNeg更小。
所以对所有合法保留位数:
取:
的最小值,就是最终答案。
复杂度分析
状态只和“当前处理到哪里、最终保留多少位”有关,用滚动数组即可。
- 时间复杂度:
- 空间复杂度:
由于答案最多有 位,需要使用高精度整数。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def solve() -> None:
n, k = map(int, input().split())
x = input().strip()
y = input().strip()
diff = [abs(int(a) - int(b)) for a, b in zip(x, y)]
pow10 = [1] * (n + 1)
for i in range(1, n + 1):
pow10[i] = pow10[i - 1] * 10
max_val = [None] * (n + 1)
min_val = [None] * (n + 1)
best_pos = [None] * (n + 1)
best_neg = [None] * (n + 1)
last = diff[-1]
max_val[1] = last
min_val[1] = -last
best_pos[1] = last
best_neg[1] = -last
for i in range(n - 2, -1, -1):
new_max = [None] * (n + 1)
new_min = [None] * (n + 1)
new_pos = [None] * (n + 1)
new_neg = [None] * (n + 1)
d = diff[i]
for t in range(1, n - i + 1):
cand = []
if max_val[t] is not None:
cand.append(max_val[t])
if t >= 2 and max_val[t - 1] is not None:
cand.append(d * pow10[t - 1] + max_val[t - 1])
if cand:
new_max[t] = max(cand)
cand = []
if min_val[t] is not None:
cand.append(min_val[t])
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力
查看10道真题和解析