【笔试刷题】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 小姐拿到了两个都是 位的十进制数 。已知在每一个对应数位上,这两个数的数字都不相同。

她可以进行两类操作:

  1. 交换操作:选择某一位,把 在这一位上的数字互换。
  2. 删除操作:选择某一位,把两个数在这一位上的数字同时删除,然后把剩余数字按原顺序重新拼接。

补充限制如下:

  • 删除后允许出现前导零。
  • 最低位不能删除。
  • 删除操作最多执行 次。
  • 交换操作可以执行任意次。

请你求出,在最多删除 位的前提下,两个数差的绝对值最小可以是多少。

输入格式

第一行输入两个整数

第二行输入十进制数

第三行输入十进制数

保证:

  • 都恰好是 位数;
  • 对任意位置 ,都有

输出格式

输出一个整数,表示最小可能的绝对差值。

样例输入

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%内容,订阅专栏后可继续查看/也可单篇购买

互联网刷题笔试宝典 文章被收录于专栏

互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力

全部评论

相关推荐

03-17 23:54
黑龙江大学 Java
来个白菜也好啊qaq:可以的,大厂有的缺打手
点赞 评论 收藏
分享
03-04 22:33
已编辑
天津大学 前端工程师
查看10道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务