【笔试刷题】米哈游-2025.10.26-改编真题
✅ 秋招备战指南 ✅
💡 学习建议:
- 先尝试独立解题
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线180+套真题改编解析,后续会持续更新的
春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗
米哈游-2025.10.26
题目一:基因序列修复
1️⃣:枚举所有长度为 26 的子串
2️⃣:逐位比较每个子串与目标字母序列的差异
3️⃣:统计不同字符数作为修改次数,取最小值
难度:中等
这道题的核心在于理解题目要求和使用滑动窗口技巧。关键观察是目标序列长度固定为 26,因此只需枚举所有长度为 26 的子串,比较每个子串与"abcdefghijklmnopqrstuvwxyz"的差异,统计需要修改的字符数即可。时间复杂度 ,对于给定的数据范围完全可以接受。
题目二:能量场扩张计划
1️⃣:检查原始能量波动值是否已满足条件
2️⃣:观察增幅操作的特性,选择包含右端点的区间最优
3️⃣:枚举区间长度,找到最小的满足条件的长度
难度:中等
这道题需要理解增幅操作的数学性质。关键观察是增幅操作只能增加数值,且为了最大化波动值,应该选择包含数组最右端点的区间进行增幅。通过数学推导,将问题转化为枚举区间长度,找到第一个使波动值超过阈值的长度。算法简洁高效,时间复杂度 。
题目三:网络延迟统计
1️⃣:通过 DFS 建立树的父子关系和遍历序列
2️⃣:使用树形 DP 计算每个节点的子树信息
3️⃣:维护子树大小、距离和、节点对距离和三个状态
4️⃣:后序遍历合并子树信息,O(1) 回答查询
难度:中等偏难
这道题是经典的树形动态规划问题。难点在于设计合适的状态和状态转移方程。通过维护子树大小、节点到子树内所有节点的距离和、子树内所有节点对的距离和这三个信息,可以高效地合并子树。关键技巧是在合并不同子树时,计算跨子树的节点对距离贡献。预处理 ,每次查询
,总时间复杂度
。
01. 基因序列修复
问题描述
K 小姐在生物实验室工作,她正在研究一段特殊的基因序列。实验室要求基因样本中必须包含完整的 26 个字母标记序列"abcdefghijklmnopqrstuvwxyz"(按顺序排列)才能进行下一步实验。
现在 K 小姐手中有一段长度为 的基因序列
,序列仅由小写字母组成,下标从
开始。她可以使用基因编辑技术对序列进行修复:
- 选择一个位置
,将
修改为任意小写字母。
每次修改都需要耗费一定的实验成本。请帮助 K 小姐计算,最少需要修改多少个位置,才能让基因序列中出现完整的 26 字母标记序列"abcdefghijklmnopqrstuvwxyz"。
名词解释
- 子串:子串为从原字符串中连续地选择一段字符(可以全选、可以不选)得到的新字符串。
输入格式
第一行包含一个整数 ,表示测试数据组数。
接下来每组测试数据包含两行:
-
第一行包含一个整数
,表示基因序列的长度。
-
第二行包含一个长度为
、仅由小写字母构成的字符串
。
保证所有测试数据中 的总和不超过
。
输出格式
对于每组测试数据,输出一行一个整数,表示最少的修改次数。
如果基因序列长度不足以包含完整的 26 字母标记序列,输出 。
样例输入
3
37
abcdefghijklmnopqrstuvwxyzzzzzzzzzzzz
26
bcdefghijkimnopqrstuvwxyza
25
abcdefghijklmnopqrstuvwxy
样例输出
0
26
-1
| 样例 | 解释说明 |
|---|---|
| 样例1 | 基因序列前 26 个字符已经是完整的字母序列,无需修改 |
| 样例2 | 无论选择哪个长度为 26 的子串,都需要修改全部 26 个字符才能得到目标序列 |
| 样例3 | 基因序列长度不足 26,无法包含完整的字母序列 |
数据范围
题解
这道题的核心思路是利用滑动窗口来枚举所有可能的长度为 26 的子串,然后计算每个子串与目标字母序列"abcdefghijklmnopqrstuvwxyz"的差异。
首先需要判断特殊情况:如果基因序列长度 ,那么无论如何都不可能包含长度为 26 的子串,直接输出
。
对于长度足够的基因序列,关键观察是:要让序列中包含完整的 26 字母序列,我们需要找一个连续的长度为 26 的位置,把它修改成"abcdefghijklmnopqrstuvwxyz"。为了最小化修改次数,应该选择一个与目标序列最相似的位置。
具体做法:
- 枚举所有可能的起始位置
(从 0 到
)
- 对于每个起始位置,检查子串
与目标字母序列的差异
- 统计有多少个位置的字符不同,这就是修改该子串所需的次数
- 取所有可能位置中的最小值
时间复杂度分析:外层循环遍历 个起始位置,内层循环比较 26 个字符,总时间复杂度为
。由于所有测试数据的
总和不超过
,这个复杂度完全可以接受。
有一个小优化:如果在枚举过程中发现某个位置已经完全匹配(修改次数为 0),可以直接输出 0 并结束,无需继续枚举。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def solve():
# 读取测试组数
T = int(input())
# 目标字母序列
tgt = "abcdefghijklmnopqrstuvwxyz"
for _ in range(T):
# 读取序列长度和内容
n = int(input())
seq = input()
# 长度不足26,无法包含完整序列
if n < 26:
print(-1)
continue
# 初始化最小修改次数为26(最坏情况)
res = 26
# 枚举所有长度为26的子串
for i in range(n - 25):
# 统计当前子串与目标的差异
cnt = 0
for j in range(26):
if seq[i + j] != tgt[j]:
cnt += 1
# 更新最小值
res = min(res, cnt)
# 如果已经完美匹配,直接退出
if res == 0:
break
print(res)
if __name__ == "__main__":
solve()
- Cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
// 目标字母序列
string tgt = "abcdefghijklmnopqrstuvwxyz";
while (T--) {
int n;
string seq;
cin >> n >> seq;
// 长度不足26,无解
if (n < 26) {
cout << -1 << "\n";
continue;
}
// 初始化答案为最大可能值
int ans = 26;
// 滑动窗口:枚举所有起始位置
for (int i = 0; i + 26 <= n; i++) {
int diff = 0;
// 逐位比较当前窗口与目标序列
for (int j = 0; j < 26; j++) {
if (seq[i + j] != tgt[j]) {
diff++;
}
}
// 更新最小修改次数
ans = min(ans, diff);
// 完美匹配,提前退出
if (ans == 0) break;
}
cout << ans << "\n";
}
return 0;
}
- Java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(System.out);
int T = Integer.parseInt(br.readLine());
// 目标字母序列
String target = "abcdefghijklmnopqrstuvwxyz";
while (T-- > 0) {
int n = Integer.parseInt(br.readLine());
String seq = br.readLine();
// 长度不足26,输出-1
if (n < 26) {
pw.println(-1);
continue;
}
// 记录最少修改次数
int minCnt = 26;
// 遍历所有可能的长度为26的子串
for (int i = 0; i + 26 <= n; i++) {
int diffCnt = 0;
// 统计当前子串与目标的差异数
for (int j = 0; j < 26; j++) {
if (seq.charAt(i + j) != target.charAt(j)) {
diffCnt++;
}
}
// 更新最小值
minCnt = Math.min(minCnt, diffCnt);
// 找到完美匹配,直接跳出
if (minCnt == 0) break;
}
pw.println(minCnt);
}
pw.flush();
pw.close();
}
}
02. 能量场扩张计划
问题描述
A 先生正在开发一个能量场系统。系统中有 个能量节点,按位置从左到右排列,每个节点有一个能量值
,满足非严格递增关系(即
)。
为了提升系统的能量波动范围,A 先生可以选择对连续的一段节点进行能量增幅操作,且这个操作至多执行一次:
- 选择区间
,对每个位置
的节点,将其能量值增加
,其中
是系统预设的增幅系数。
也就是说,区间内靠右的节点会获得更多的能量增幅。
A 先生希望知道,要使得操作后整个系统的能量波动值(最大能量值与最小能量值之差)严格大于 ,至少需要选择多长的区间进行增幅。如果不进行操作也能满足条件,输出
;如果无论如何都无法满足条件,输出
。
名词解释
- 能量波动值:数组中最大值与最小值的差值,例如能量序列
的波动值为
。
输入格式
第一行包含一个整数 ,表示测试数据组数。
每组测试数据包含两行:
-
第一行包含三个整数
,分别表示节点数量、目标波动值和增幅系数。
-
第二行包含
个非严格递增的整数
,表示各节点的初始能量值。
保证所有测试数据中 。
输出格式
对于每组测试数据,输出一行一个整数,表示满足条件的最小区间长度。如果原始状态已满足条件,输出 ;如果无法满足条件,输出
。
样例输入
3
4 5 2
1 3 5 7
3 10 1
2 6 8
3 8 5
1 2 3
样例输出
0
-1
2
| 样例 | 解释说明 |
|---|---|
| 样例1 | 原始能量序列波动值为 |
| 样例2 | 原始波动值为 |
| 样例3 | 选择长度为 2 的区间 |
数据范围
题解
这道题的关键在于观察增幅操作的特性,找出最优策略。
首先,如果原始序列的波动值 已经大于
,那么无需任何操作,直接输出
。
接下来分析如何通过增幅操作最大化波动值。注意到:
- 增幅操作只能增加能量值,不能减少
- 序列本身是非严格递增的
- 增幅后,区间内靠右的位置增加更多
为了最大化波动值 ,有两种思路:
- 最大化最大值:应该选择包含最右端点
的区间
- 最小化最小值:由于只能增加不能减少,最小值始终是
因此最优策略是选择形如 的右端区间,这样可以让
获得最大增幅。
假设选择长度为 的区间
,那么:
- 区间左端点
会增加
- 新的最大值为
- 最小值仍为
- 新的波动值为
我们需要找最小的 ,使得:
注意区间长度不能为 (至少要保留一个位置不增幅,否则波动值不变)。
可以从 开始枚举,找到第一个满足条件的长度。如果枚举完所有长度都不满足,输出
。
时间复杂度:每组数据 ,总复杂度
,可以通过。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def solve():
# 读取测试组数
T = int(input())
for _ in range(T):
# 读取参数
n, d, k = map(int, input().split()
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力
MDPI公司福利 417人发布