华为2026.5.20暑期实习笔试真题 - AI岗
最新暑期实习/春招/秋招大厂笔试真题汇总:
https://svih06ofn7v.feishu.cn/wiki/E4SBwR7ZKiSZxpkRVZCcmjI9nBl
AK机给大家整理了一份高质量的互联网大厂、大模型独角兽的内推和暑期实习/春秋招投递信息汇总,每日更新,建议收藏:
https://docs.qq.com/smartsheet/DUXJLSnZoTVFhVUVs?tab=sc_K49vrh
华为 27 届暑期实习 AI 岗的机考又开了一场,本场依旧是「20 道选择题 + 2 道编程题」的经典配置,覆盖数学、机器学习、大模型工程以及偏算法的两道 Hard 题。AK机第一时间整理了完整题解与 Python 代码,希望能帮助大家更好地准备后续笔试。
本场考试概述
考试时间:2026 年 5 月 20 日
考试岗位:华为暑期实习 AI 岗(AI算法、AI应用开发、AI数据科学等以 AI 为前缀的岗位)
难度评级:困难
考点分析:
• 选择题(20 道):涵盖多项式拟合、线性代数(零空间/行列式)、数值方法(共轭梯度/弦截法/直接法迭代法)、L2 正则化、聚类鲁棒性、特征工程,以及大模型工程(PagedAttention/KV Cache/Prefill-Decode/对齐失效/量化)等核心方向 • 第一题:多源语料分级清洗(困难,二维费用分组背包) • 第二题:敏感实体动态遮蔽掩码(困难,KMP + 差分扫描)
建议策略:
• 华为 AI 岗选择题题量大且覆盖面广,复习时要同时兼顾大模型推理工程(KV Cache 计算、PagedAttention、PD 分离)和经典数值/线代基础(条件数、迭代法收敛阶、行列式与秩) • 两道编程题都属于"模型清晰但状态/转移繁琐"类型,重点是把题面的多维约束准确翻译成 DP 状态或差分数组,不要急着上滚动数组 • 第一题分组背包必须用三维状态 f[i][b][t],把 i 维显式写出来;第二题 KMP 后用差分代替显式区间合并,扫描时用 base/inside 双指针计数
1、用二次多项式拟合下列数据点:。则拟合多项式的一次项系数最接近:
A.
B.
C.
D.
答案:B
难度:入门
考点:数学—数值/多项式拟合
解释:四个数据点严格满足 ,二次拟合在最小二乘意义下退化为这条直线,故二次项系数为 ,一次项系数为 ,常数项为 。
2、在计算机渲染 3D 模型时通常会使用双线性插值处理纹理映射,与最近邻插值相比,双线性插值主要可以减少:
A. 计算时间
B. 精度损失
C. 视觉锯齿
D. 数据存储
答案:C
难度:入门
考点:数学—插值
解释:双线性插值用 邻域像素加权平均得到目标颜色,过渡平滑,消除了最近邻在边缘和斜线处典型的"阶梯状锯齿"。A 计算时间反而增加;B 严格意义的"精度"并不必然提升;D 与数据存储无关。
3、在多智能体强化学习中,智能体的联合状态向量组构成矩阵 ,则矩阵 的零空间维度为()
A.
B.
C.
D.
答案:C
难度:简单
考点:数学—线性代数
解释:第二行是第一行的 倍,矩阵秩 ,由秩-零度定理 。
4、预条件共轭梯度法(PCG)中,预条件矩阵 的选取目标是使得 的条件数:
A. 无所谓
B. 尽可能接近
C. 等于 的条件数
D. 尽可能大
答案:B
难度:中等
考点:数学—数值优化
解释:CG 类迭代法收敛速率上界与系数矩阵条件数 直接相关(误差衰减因子约为 )。 意味着 接近单位阵,收敛最快。
5、在训练神经网络时,使用带 L2 正则化的损失函数 。关于正则化系数 ,下列说法正确的是:
A. 时,正则化效果最强,模型最简
B.的选择与模型过拟合或欠拟合无关,只需固定为常用值如
C.越大,模型越倾向于拟合训练数据,泛化能力越强
D. 越大,对权重参数的惩罚越重,模型复杂度越低
答案:D
难度:入门
考点:机器学习—正则化
解释:L2 正则将加到损失里,越大优化器越倾向让变小,等价于偏好简单模型。A 反了,时没有正则;B 显然错;C 大 偏向欠拟合而非拟合训练集。
6、PagedAttention 的核心设计目标是解决 AI 模型推理中的()
A. 重计算导致的推理延迟过高问题
B. 显存碎片化,导致显存利用率低下问题
C. 模型量化后精度损失问题
D. KV Cache 占用显存过大问题
答案:B
难度:中等
考点:大模型—推理优化
解释:PagedAttention(vLLM)把 KV Cache 按固定大小的"页"管理,类似操作系统虚拟内存的分页机制,消除了因变长序列产生的外部碎片,显著提升显存利用率。D 是常见误解:PagedAttention 并不减小 KV Cache 总量,只是减少浪费。
7、在大语言模型的安全对齐(Alignment)过程中,主要目标是确保模型输出符合人类价值观且无害。以下关于"对齐失效"的描述中,哪一项是最常见的风险场景?
A. 模型推理速度过慢,导致用户等待时间过长从而放弃使用
B. 模型词汇表过小,无法理解生僻的专业术语
C. 模型在训练过程中损失函数无法收敛,导致无法生成任何文本
D. 模型在面对恶意诱导 prompt 时,绕过安全限制生成有害内容(如制造武器教程)
答案:D
难度:入门
考点:大模型—对齐与安全
解释:对齐失效(misalignment)的典型表现是 jailbreak/越狱:通过精心构造的 prompt 让模型绕过 RLHF 训练出的拒答策略,输出本应拒绝的有害内容。A、B、C 是性能或工程问题,不属于对齐失效。
8、弦截法(割线法,用两点连线的斜率代替导数来求根)的收敛阶约为:
A. 阶
B. 阶
C. 阶
D. 阶
答案:D
难度:中等
考点:数学—数值方法
解释:割线法的收敛阶恰好等于黄金比例 ,介于线性()与牛顿法的二次()之间,是经典数值分析结论。
9、关于 KV Cache 在自回归推理中的作用,最准确的是:
A. 减少参数量,从而降低模型存储体积
B. 提升训练收敛速度
C. 缓存历史 token 的 K/V,避免每步重复计算
D. 让模型在推理时不再需要注意力机制
答案:C
难度:入门
考点:大模型—推理优化
解释:自回归解码每生成一个 token 都要做一次 Attention,历史 token 的 K、V 在后续步骤中保持不变,缓存起来即可省掉每步的重复线性变换,把单步复杂度从 降到 。A、B 与 KV Cache 无关;D 注意力机制依然存在。
10、在 LLM 推理中,prefill 阶段和 decoding 阶段的计算瓶颈不同。以下分析正确的是:
A. 两个阶段都是 compute-bound,区别仅在于序列长度不同
B. prefill 阶段是 memory-bound,decoding 阶段是 compute-bound
C. prefill 阶段并行处理整个输入序列,矩阵乘法密集,是 compute-bound;decoding 阶段每步生成一个 token,需反复加载全部权重,是 memory-bound
D. KV Cache 使 decoding 阶段变为 compute-bound,因为节省了大量访存
答案:C
难度:中等
考点:大模型—推理优化
解释:prefill 处理整个 prompt,可在 batch/sequence 维度并行做大 GEMM,算术强度高;decoding 一次只产 个 token,但每步都要把所有权重从显存搬到计算单元,瓶颈在显存带宽。这正是 PD 分离、continuous batching 等技术的出发点。
11、如果数据集存在明显的噪声点和离群值,哪种聚类算法表现最稳健?
A. GMM(高斯混合模型)
B. DBSCAN
C. 谱聚类
D. K-Means
答案:B
难度:入门
考点:机器学习—聚类
解释:DBSCAN 将密度不足的点直接标为 noise(标签 ),不会强行分配到任何簇,对离群值天然鲁棒。K-Means / GMM 的均值与方差估计都对离群点敏感;谱聚类也会被异常点拉偏。
12、在图像处理中,将一张 的 RGB 图像展平为一维向量,其维度是?
A.
B.
C.
D.
答案:A
难度:入门
考点:深度学习—CNN/数据维度
解释:,三通道展平后总维度为长 宽 通道数。
13、某大模型团队正在优化推理服务的显存占用。已知模型配置:隐藏层维度 hidden size ,Transformer 层数 ,注意力头数 。推理时使用 FP16( 字节)存储 KV Cache,最大序列长度 ,Batch Size 。最大上下文长度下,存储 KV Cache 所需的显存最接近:
A. GB
B. GB
C. GB
D. GB
答案:D
难度:中等
考点:大模型—KV Cache 显存估算
解释:标准公式。代入字节,约GB。系数是 K + V,是层数,是序列长, 是 hidden size。
14、在某应用的商品推荐系统中,用户行为包括停留时长、是否收藏等,这些数据通过向量来表示。如果要计算两个用户向量相似度,最常用的度量是:
A. 皮尔逊相关系数
B. 余弦相似度
C. 曼哈顿距离
D. 欧氏距离
答案:B
难度:入门
考点:机器学习—推荐系统
解释:推荐系统中的用户/物品向量通常对绝对量级不敏感,关心的是方向(兴趣分布)。余弦相似度衡量夹角、忽略模长,是协同过滤和向量召回的事实标准。
15、Scaled Dot-Product Attention 中除以 的原因是:
A. 保证 和 的内积严格服从标准正态分布
B. 让注意力权重之和归一化为
C. 减少矩阵乘法的计算量
D. 防止点积结果过大使 Softmax 进入梯度极小的饱和区,导致训练困难
答案:D
难度:中等
考点:深度学习—Transformer
解释:若各分量独立同分布且方差为,则方差正比于,未缩放时 logits 会随维度变大,Softmax 进入饱和区导致梯度消失。除以把方差归一到,保持梯度尺度稳定。
16、针对 Prefill 和 Decode 阶段的性能差异,现代推理引擎通常会采用哪些策略来优化整体吞吐量?
A. 在 Decode 阶段强制使用 GEMM 代替 GEMV 进行计算
B. 将 Prefill 和 Decode 阶段在不同的 GPU 节点上进行分离部署(PD 分离)
C. Continuous Batching(连续批处理)以提升 Decode 阶段的并发度
D. Chunked Prefill(分块预填充)以避免长 Prompt 阻塞 Decode 进程
答案:B, C, D
难度:中等
考点:大模型—推理优化
解释:B 把 compute-bound 的 Prefill 与 memory-bound 的 Decode 分到不同硬件,可独立扩缩;C 不等批次满就发车,让 Decode 阶段把空闲 batch slot 持续填满,显著抬高吞吐;D 把超长 prompt 切片,避免一个长 Prefill 卡死整个调度。A 单 token Decode 只有 GEMV,没办法强行变成 GEMM,且与"提升吞吐"无关。
17、在矩阵运算中,下列哪些情况可能导致矩阵的行列式为零?
A. 矩阵是可逆矩阵
B. 矩阵的秩小于其阶数
C. 矩阵是奇异矩阵
D. 两个非零矩阵相乘的结果可能是零矩阵
答案:B, C, D
难度:简单
考点:数学—线性代数
解释:B 秩亏即列向量线性相关,;C "奇异"的定义就是 ;D 例如 ,乘积可为零矩阵且 。A 可逆矩阵恰好 ,错误。
18、以下关于直接法和迭代法求解线性方程组的比较,正确的有:
A. 迭代法适合求解大型稀疏方程组
B. 高斯消元法属于直接法
C. Jacobi 和 Gauss-Seidel 方法属于迭代法
D. 直接法经过有限步运算可得到精确解(理论上)
答案:A, B, C, D
难度:入门
考点:数学—数值方法
解释:四项均为基础结论。A 迭代法避免对稀疏结构做填充;B 高斯消元、LU 分解为代表的直接法;C Jacobi、Gauss-Seidel、SOR 都是定点迭代;D 直接法在精确算术下有限步终止,区别于迭代法的渐近收敛。
19、下列哪些算子通常不建议进行低比特量化?
A. LayerNorm
B. Softmax
C. RoPE(旋转位置编码)
D. MatMul(矩阵乘法)
答案:A, B, C
难度:中等
考点:大模型—量化
解释:A LayerNorm 含均值/方差与小数值除法,量化误差被放大;B Softmax 的指数函数对输入扰动敏感,且输出已是概率范围,几乎没有量化收益;C RoPE 涉及三角函数与高频相位,低比特会严重破坏相对位置关系。D MatMul 是量化收益最大且最成熟的算子(INT8/INT4 主战场),常规做法是只量化它而保留前三者为高精度。
20、在构建高维机器学习模型时,关于特征工程中的转换与评估,下列说法中正确的有:
A. 在使用目标编码(Target Encoding)时,即使采用了平滑技术,若类别的样本量极小,该特征在验证集上的表现仍可能因为"条件概率估计不准"而导致严重的过拟合
B. 对于具有偏态分布(Skewed Distribution)的数值特征,使用 Box-Cox 变换不仅能使数据更接近正态分布,还能在一定程度上起到稳定方差(Homoscedasticity)的作用
C. Weight of Evidence (WoE) 编码主要用于逻辑回归(Logistic Regression),它的数学本质是将非线性特征转换为线性空间,且能够处理缺失值并具有较好的解释性
D. 在特征选择中,过滤式(Filter)方法比包裹式(Wrapper)方法更倾向于选出对模型最终性能最优的特征子集,因为过滤式方法不依赖于具体的算法偏差
答案:A, B, C
难度:困难
考点:机器学习—特征工程
解释:A 目标编码的低频类别条件概率估计方差大,即便加平滑也只是收缩,仍易过拟合;B Box-Cox 通过参数化幂变换同时实现近正态化与方差稳定;C WoE 把类别特征映射为对数似然比,让特征与 logit 线性,特别契合 LR,并可把缺失视为独立分箱。D 反了,Wrapper 直接以模型性能为目标更可能选出"最优"子集,Filter 只是更通用、更快,并不保证对特定模型最优。
第1题:多源语料分级清洗
题目描述
某 LLM 预训练团队从 个数据源收集语料,每个数据源具有以下属性:表示该数据源占总训练 token 的权重比例,所有之和恰好为;表示初始脏数据比例,满足;是基础清洗单价(正整数); 是基础清洗算力消耗(正整数)。
对每个数据源,可独立选择以下四种清洗级别之一:
整体语料的加权污染率定义为:
在总花费不超过预算 且总算力消耗不超过算力上限 的前提下,为每个数据源选择一个清洗级别,使得加权污染率 最小。请输出可达到的最小加权污染率,结果保留 位小数。
输入描述
第一行包含三个整数 ,分别表示数据源数量、总预算上限和总算力上限。
接下来 行,每行包含四个数,依次为第个数据源的权重比例、初始脏数据比例、基础清洗单价、基础清洗算力消耗。保证所有之和为,与至多保留 位小数。
输出描述
输出一个浮点数,表示在预算 与算力 限制下可达到的最小加权污染率,保留 位小数,不包含多余空格或换行。
样例1
输入
3 10 7
0.4 0.5 2 2
0.3 0.7 3 3
0.3 0.4 1 1输出
0.270000样例解释
方案 :源选级 + 源选级,源不清洗。花费,算力,。
方案 :源选级 + 源选级,源不清洗。花费,算力,。
方案 :源选级 + 源选级 + 源选级。花费,算力,。
方案 最优,答案为 。
样例2
输入
2 6 4
0.5 0.8 2 2
0.5 0.6 3 1输出
0.380000样例解释
方案 (源选级,源选级):花费、算力,。
方案 (源选级,源选级):花费、算力,。
方案 (源选级,源选级):花费、算力,。
方案 最优,答案为 。
题解:二维费用分组背包
题目问题拆解
每个数据源必须从 种清洗级别里恰选 种,每种级别有两个独立维度的开销(花费、算力)和一份污染率收益。题目本质是 「分组背包 + 二维费用」 的最大化收益问题,约束规模 ,复杂度 完全可行。
算法实现
等价变换:
最小化污染率不好直接做 DP(每选一级是"乘法压缩"),换个角度处理——先把所有数据源都按"等级 "算出初始污染率:
第 个数据源选等级 时,污染率从 降到 ,减少量为:
问题等价于"在双重容量限制下让减少量之和最大",正好是分组背包的最大化形式。
三张常数表:
直接照抄题目给的四档等级,方便代码下标访问:
等级 的花费、算力分别为 、。
状态方程定义:
第一维 是组号,确保每组只贡献一次;后两维 是二维费用。
状态方程初始化:
只有"一个数据源都没处理、花费算力都为 "这一个起点合法。 标记不可达,避免与合法的零收益混淆。
状态方程转移:
从 推到 时,第 个数据源有 种选法,分两类写:
等级 (不清洗)——状态原样继承:
等级 (设当前等级花费 、算力 、收益 )——和默认继承值取较大:
注意右侧的下标是 而不是 ——这是分组背包的关键 trick。因为始终从上一层读、向当前层写,同一数据源的多个等级互相之间永远看不到对方的选择,"恰选一个"约束天然成立。如果错写成 就退化成完全背包,会把同一数据源选多次。
最终答案:
在第 层枚举所有满足约束的状态取最大值,再减回 :
双精度浮点累加会引入 级误差,当 时夹回 ,再以 %.6f 输出。
时空复杂度分析
时间复杂度:,。代入上界 , 秒可过。
空间复杂度:,三维数组约 个 double MB,在 MB 限制内。
Python
# 多源语料分级清洗 - 二维费用分组背包
import sys
from array import array
data = sys.stdin.read().split()
idx = 0
n = int(data[idx]); idx += 1
B = int(data[idx]); idx += 1
T = int(data[idx]); idx += 1
w = [0.0] * n
r = [0.0] * n
c = [0] * n
p = [0] * n
for i inrange(n):
w[i] = float(data[idx]); idx += 1
r[i] = float(data[idx]); idx += 1
c[i] = int(data[idx]); idx += 1
p[i] = int(data[idx]); idx += 1
# 四种清洗等级对应的花费倍率、算力倍率、脏数据保留比例
cost_mul = [0, 1, 3, 6]
power_mul = [0, 1, 2, 3]
rate = [1.0, 0.6, 0.2, 0.0]
# f[i][b][t]:处理完前 i 个数据源,已花费 b、已使用算力 t 时的最大"污染率减少量"
# 内层用 array('d') 存连续 double,避免 Python list 的 PyFloat 装箱开销
NEG = -1e18
f = [[array('d', [NEG]) * (T + 1) for _ inrange(B + 1)] for _ inrange(n + 1)]
f[0][0][0] = 0.0
# base 表示所有数据源都不清洗时的初始加权污染率
base = sum(w[i] * r[i] for i inrange(n))
for i inrange(n):
origin = w[i] * r[i]
for b inrange(B + 1):
fi = f[i][b]
fi1 = f[i + 1][b]
for t inrange(T + 1):
# 等级 0:不清洗,状态原样从上一层继承
fi1[t] = fi[t]
# 等级 1/2/3:枚举每个等级,看能否得到更大的减少量
for lv inrange(1, 4):
cb = cost_mul[lv] * c[i]
ct = power_mul[lv] * p[i]
if cb > b or ct > T:
continue
gain = origin * (1.0 - rate[lv])
fprev = f[i][b - cb]
for t inrange(ct, T + 1):
v = fprev[t - ct]
if v <= NEG / 2:
continue
cand = v + gain
if cand > fi1[t]:
fi1[t] = cand
# 在最后一层所有状态里取最大减少量
best = 0.0
for row in f[n]:
for v in row:
if v > best:
best = v
ans = base - best
# 浮点误差可能让答案略小于 0,统一钳到 0
if -1e-9 < ans < 0:
ans = 0.0
print(f"{ans:.6f}", end='')第2题:敏感实体动态遮蔽掩码
题目描述
为了防止大语言模型记忆并泄露输入上下文的敏感数据,安全框架会对输入的长文本进行预扫描,匹配预设的敏感词库(如 API_KEY、身份证号码等)。一旦在序列中发现了敏感词,系统会在底层的注意力掩码矩阵中对这些"敏感区块"进行动态隔离遮蔽。具体来说,敏感区块内部的 token 可以互相看到,但外部的任何 token 都绝对不能看到这些敏感数据。
给定一个长度为 的主序列 token 数组 ,以及 个敏感模式串。
第一步:模式匹配与敏感区块合并。在主序列 中找出所有敏感模式串的出现位置,得到一组闭区间。若两个区间与相交()或首尾相邻(或),则需要合并为一个连续敏感块。
第二步:动态遮蔽掩码。对于序列中的任意位置 和目标位置(遵循因果律),能否观察到由以下规则决定:隔离规则——如果属于某个敏感块,那么只有当也身处同一个敏感块内部时,才能观察到;正常规则——如果不属于任何敏感块,则它对所有满足 的位置正常可见。
请输出每个位置 在整个序列中总共能观察到多少个 token(包含自身)。
输入描述
第一行包含两个整数 ,分别为主序列长度和敏感模式串的数量。
第二行包含 个整数 ,以空格分隔,代表主序列的 token 数组。
接下来 行,每行首先是一个整数 ,代表敏感模式串长度,后面跟着 个整数(每个值在 之间),以空格分隔,代表该敏感模式串的 token 值。
输出描述
输出 个整数,以空格分隔,代表每个位置 在整个序列中总共能观察到的 token 数量。
样例1
输入
7 2
10 20 30 40 50 60 70
3 20 30 40
2 40 50输出
1 2 3 4 5 2 3样例解释
模式串 在主序列中的索引区间为 ;模式串 在主序列中的索引区间为 。两个区间相交,合并为敏感块 。
位置 (值 ,正常):可看到自身,答案 。
位置 (敏感块内):可看前面 个正常 token,再加上敏感块内已走过的 token 数,依次为 。
位置 (值 ,正常):可看到自身及前面 个正常 token,答案 。
位置 (值 ,正常):答案 。
样例2
输入
9 1
10 20 30 40 50 60 30 40 70
2 30 40输出
1 2 3 4 3 4 5 6 5样例解释
模式串 在主序列中出现两次:索引区间 与 。两段不相邻,形成两个独立敏感块。
位置 (正常):答案 。
位置 (敏感块一):可看到前 个正常 token,加块内走过的 token 数,依次为 。
位置 (正常):答案 。
位置 (敏感块二):可看到前 个正常 token,加块内走过的 token 数,依次为 。
位置 (正常):答案 。
题解:KMP + 差分扫描
题目问题拆解
题目可以拆成两件独立的事。
第一件事:找出所有"敏感区间"并合并。每个敏感模式串都可能在主序列里出现多次,要把这些出现位置 全部找到,再把相交或首尾相邻的合并成一个连续的"敏感块"。
第二件事:按因果约束 给每个位置 计数。规则只有两条:
规模上界 ,匹配阶段 ,扫描阶段 ,整体在 量级。
算法实现
KMP 找匹配:
对每个模式串单独跑一次 KMP。先用 时间构造前缀函数 :
意思是 记录" 这一段,其最长的相同前缀与后缀的长度"。匹配主串时遇到失配就跳到 继续比,无需回退主串指针。
一次完整匹配 之后不要重置,而是 。这样能继续找出与当前匹配位置重叠的下一次出现(比如 pat = ababa 在主串 ababababa 中会有重叠匹配)。
差分合并区间:
找到匹配区间 (其中 ,)后,不必显式存所有区间。开一个差分数组 ,每次匹配只做两次单点修改:
扫描时维护前缀和 。判定规则极其简洁:
相邻和相交的区间在前缀和上自动连成一段连续的正值,无需手写"区间合并"代码。
扫描计数:
从左到右遍历,维护四个变量:
base 是关键 trick:在敏感块开始那一刻"拍照",记下块外已积累了多少普通 token;进了块以后这个数就被冻结,块内 token 看到的就是这一份外部前缀。
按位置 分两种情况输出:
普通分支的可见集合 = 前缀里所有普通 token,正好是更新后的 。
敏感分支的可见集合分两部分:块外可见的前缀普通 token = ;块内 的 token = 。
二者相加就是答案。
时空复杂度分析
时间复杂度:单次 KMP 构造 + 匹配为 ; 个模式串总匹配为 。扫描计数为 。
代入上界 ,远低于 秒时限。
空间复杂度:。主序列、差分数组、答案数组各 ,每个模式串及其 数组各 用完即释放。
Python
# 敏感实体动态遮蔽掩码 - KMP + 差分扫描
import sys
defmark_pattern(arr, pat, diff):
"""KMP 找 pat 在 arr 中所有匹配,把闭区间 [l, r] 加到差分数组上。"""
m = len(pat)
# pi[i] 是 pat[0..i] 的最长相等真前后缀长度
pi = [0] * m
j = 0
for i inrange(1, m):
while j > 0and pat[i] != pat[j]:
j = pi[j - 1]
if pat[i] == pat[j]:
j += 1
pi[i] = j
j = 0
for i, x inenumerate(arr):
while j > 0and x != pat[j]:
j = pi[j - 1]
if x == pat[j]:
j += 1
if j == m:
l = i - m + 1
# 闭区间 [l, i] 用差分标记
diff[l] += 1
diff[i + 1] -= 1
# 允许重叠匹配也被纳入统计
j = pi[j - 1]
data = sys.stdin.buffer.read().split()
idx = 0
n = int(data[idx]); idx += 1
k = int(data[idx]); idx += 1
arr = list(map(int, data[idx:idx + n]))
idx += n
# 差分数组多开一格,方便闭区间右端 +1
diff = [0] * (n + 1)
for _ inrange(k):
m = int(data[idx]); idx += 1
pat = list(map(int, data[idx:idx + m]))
idx += m
if m <= n:
mark_pattern(arr, pat, diff)
ans = [0] * n
cover = 0# 当前位置被多少个敏感区间覆盖
normal = 0# 已扫描过的普通 token 数量
in_block = False
base = 0# 当前敏感块起点之前的普通 token 数
inside = 0# 当前敏感块内已扫过的 token 数
for i inrange(n):
cover += diff[i]
if cover > 0:
# 第一次进入新敏感块时锁定 base
ifnot in_block:
in_block = True
base = normal
inside = 0
inside += 1
ans[i] = base + inside
else:
in_block = False
normal += 1
ans[i] = normal
sys.stdout.write(" ".join(map(str, ans)))AK机制作的华为机考速通指南,16w字内容,234道真题覆盖全考点,助力应届生同学速成华为机考~
想要获取本场笔试代码,以及沟通交流求职等内容,可以加入下方AK机的校招交流群

夜雨聆风