大厂真题 / 米哈游

米哈游 2026-8-16 笔试真题 - 运维开发(平台向)

本场考试概述

考试时间:2026 年 8 月 16 日

考试岗位:运维开发(平台向)· 2 卷

难度评级:中等偏下

考点分析

  • 第 1 题:前缀和、值域约束剪枝(中等)
  • 第 2 题:Bash、awk 文本处理(简单)

建议策略

  • 第 1 题不要直接枚举所有子数组。由 $\lvert a_i\rvert\le 100$ 可以推出合法子数组长度不超过 $100$,据此将枚举量降到 $O(100n)$。
  • 第 2 题重点是按输入阶段读取数据,并用关联数组完成版本过滤、平台去重和原顺序输出。

第 1 题:子数组和等于长度平方

题目描述

给定一个长度为 $n$ 的整数数组 $a$。定义任意非空子数组 $[l,r]$ 的长度为

\[L=r-l+1,\]

其元素和为 $\sum_{i=l}^{r}a_i$。请统计满足

\[\sum_{i=l}^{r}a_i=L^2\]

的子数组个数。

子数组是从原数组中连续选择一段元素得到的新数组。

输入描述

每个测试文件包含多组测试数据。

第一行输入整数 $T$,满足 $1\le T\le 10^5$。

每组测试数据包含两行:

  • 第一行输入整数 $n$,满足 $1\le n\le 10^5$;
  • 第二行输入 $n$ 个整数 $a_1,a_2,\ldots,a_n$,满足 $\lvert a_i\rvert\le100$。

所有测试数据的 $n$ 之和不超过 $2\times10^5$。

输出描述

对于每组测试数据,输出一个整数,表示满足条件的子数组个数。

样例 1

输入

1
5
1 4 0 3 1

输出

4

解释

长度为 $1$ 时,数组中的两个 1 分别贡献一个答案。长度为 $2$ 时,子数组 [4,0][3,1] 的和均为 $4$,再贡献两个答案,合计为 $4$。

样例 2

输入

2
3
-1 2 3
4
1 2 2 4

输出

0
2

思路分析

预处理前缀和 prefix,其中 prefix[i] 表示前 $i$ 个元素之和。长度为 $L$、右端点为 right - 1 的子数组和可以在 $O(1)$ 时间内写成:

\[prefix[right]-prefix[right-L].\]

如果直接枚举所有长度,复杂度仍为 $O(n^2)$。关键是利用元素值域:长度为 $L$ 的子数组最多只能取得 $100L$ 的和,而题目要求其和为 $L^2$,所以必要条件为

\[L^2\le100L.\]

由于 $L>0$,可得 $L\le100$。因此只需枚举 $1$ 到 $\min(n,100)$ 的长度,再扫描所有对应子数组。

数组允许出现负数,但不影响上述上界:$100L$ 仍然是区间和的最大可能值。

正确性证明

引理 1:长度大于 $100$ 的子数组不可能满足题目条件。

证明:任意元素均不大于 $100$,因此长度为 $L$ 的子数组和不大于 $100L$。当 $L>100$ 时,$L^2>100L$,子数组和不可能达到 $L^2$。引理得证。

引理 2:算法能够正确判断每个长度不超过 $100$ 的子数组是否满足条件。

证明:前缀和之差 prefix[right] - prefix[right - L] 恰好等于该长度为 $L$ 的连续区间内所有元素之和。算法将其与 $L^2$ 比较,因此判断结果与题目定义一致。引理得证。

定理:算法输出的计数恰好等于所有满足条件的子数组数量。

证明:由引理 1,所有可能满足条件的子数组长度都在算法枚举范围内;算法对每种合法长度的所有连续区间各检查一次,没有遗漏或重复。由引理 2,每次判断均正确,所以最终计数恰好是答案。定理得证。

ACM Python 代码

import sys


def count_good_subarrays(values):
    n = len(values)
    prefix = [0] * (n + 1)
    for i, value in enumerate(values, 1):
        prefix[i] = prefix[i - 1] + value

    answer = 0
    for length in range(1, min(n, 100) + 1):
        target = length * length
        for right in range(length, n + 1):
            if prefix[right] - prefix[right - length] == target:
                answer += 1
    return answer


def solve():
    data = list(map(int, sys.stdin.buffer.read().split()))
    test_cases = data[0]
    cursor = 1
    output = []

    for _ in range(test_cases):
        n = data[cursor]
        cursor += 1
        values = data[cursor:cursor + n]
        cursor += n
        output.append(str(count_good_subarrays(values)))

    sys.stdout.write("\n".join(output))


if __name__ == "__main__":
    solve()

复杂度分析

时间复杂度为 $O(100n)$,对全部测试数据合计最多进行约 $2\times10^7$ 次区间和判断。

空间复杂度为 $O(n)$,用于保存输入数组和前缀和。

易错点

  • 不能仍按 $O(n^2)$ 枚举所有左右端点;长度上界 $100$ 是本题的核心。
  • 多组数据的 $n$ 之和有限制,应一次读取输入并顺序解析。
  • 区间和与答案计数都建议使用 64 位整数;Python 整数会自动扩容。
  • 前缀和下标要统一:长度为 $L$、右边界为 right 的区间使用 prefix[right] - prefix[right - L]

第 2 题:资源包缺失清单

题目描述

游戏活动上线前,运营平台会为每个活动场景准备一组资源包,并分别在 androidiospc 三个平台生成资源就绪记录。请根据资源计划和平台检查日志,输出仍缺少就绪记录的资源包清单。

对每条资源计划,只有在要求版本下同时存在三个平台的 READY 记录,才认为该资源包发布完整。

统计规则如下:

  • 同一资源包、同一版本、同一平台可以出现多条记录,只要至少存在一条 READY 即可;
  • FAIL 不能替代 READY
  • 非要求版本的记录不计入;
  • 未出现在资源计划中的日志忽略。

输入描述

第一行包含两个整数 $R,C$,满足 $1\le R\le10000$、$0\le C\le30000$。

随后 $R$ 行为资源计划,每行包含三个空白分隔字段:

resource_id scene required_version

再随后 $C$ 行为平台检查日志,每行包含四个空白分隔字段:

resource_id version platform status

其中 platform 只会是 androidiospcstatus 只会是 READYFAIL

各字段长度为 $1$ 到 $50$,只包含大小写字母、数字、点号、下划线和短横线。resource_id 在资源计划中互不重复,输入格式合法且不存在空行或多余空格。

输出描述

按资源计划给出的先后顺序,逐行输出每个发布不完整的 resource_id。若所有资源包均发布完整,输出 none

样例 1

输入

3 7
pkg_a scene1 v1.0
pkg_b scene1 v1.0
pkg_c scene2 v2.0
pkg_a v1.0 android READY
pkg_a v1.0 ios READY
pkg_a v1.0 pc READY
pkg_b v1.0 android READY
pkg_b v1.0 ios FAIL
pkg_b v1.0 pc READY
pkg_c v1.5 android READY

输出

pkg_b
pkg_c

样例 2

输入

2 7
pkg_x sceneA build-1
pkg_y sceneA build-1
pkg_x build-1 android FAIL
pkg_x build-1 android READY
pkg_x build-1 ios READY
pkg_x build-1 pc READY
pkg_y build-1 android READY
pkg_y build-1 ios READY
pkg_y build-1 pc READY

输出

none

思路分析

使用一个 awk 程序单遍处理输入:

  1. 首行读取资源计划数量 R
  2. 接下来的 R 行记录每个资源包的要求版本,并用 order 数组保留输入顺序。
  3. 对日志行,仅接受“资源包在计划内、版本匹配、状态为 READY”的记录。
  4. 使用 seen[resource_id, platform] 对同平台的重复 READY 去重,再累计每个资源包已就绪的平台数。
  5. END 块中按计划顺序输出就绪平台数小于 3 的资源包。

awk 的关联数组本身不保证按插入顺序遍历,因此必须额外保存 order[i]

正确性证明

引理 1:计数数组 ready_count[id] 等于资源包 id 在要求版本下拥有 READY 记录的平台种类数。

证明:日志处理条件排除了计划外资源、错误版本和 FAIL 记录;seen[id, platform] 又保证同一平台至多计数一次。因此每次增量对应一个不同且有效的平台,所有有效平台也都会被处理。引理得证。

引理 2:脚本输出且仅输出发布不完整的资源包。

证明:平台集合固定为 androidiospc。由引理 1,ready_count[id] = 3 当且仅当三个平台均已有有效 READY 记录。因此 ready_count[id] < 3 当且仅当资源包发布不完整。引理得证。

定理:脚本按资源计划顺序输出全部发布不完整的资源包;若不存在则输出 none

证明order 完整保存计划中的资源包顺序,END 块依次检查每一项,并由引理 2 准确决定是否输出。若没有任何输出项,标志变量保持为假,脚本输出 none。定理得证。

题解代码

import sys


def solve():
    data = sys.stdin.buffer.read().splitlines()
    if not data:
        return
    R, C = map(int, data[0].split())
    order, required, ready = [], {}, set()
    pos = 1
    for _ in range(R):
        resource_id, _scene, version = data[pos].decode().split()
        pos += 1
        order.append(resource_id)
        required[resource_id] = version
    for _ in range(C):
        resource_id, version, platform, status = data[pos].decode().split()
        pos += 1
        if resource_id in required and version == required[resource_id] and status == "READY":
            ready.add((resource_id, platform))
    missing = [resource_id for resource_id in order
               if sum((resource_id, platform) in ready for platform in ("android", "ios", "pc")) < 3]
    sys.stdout.write("\n".join(missing or ["none"]))


if __name__ == "__main__":
    solve()

Bash 代码

#!/usr/bin/env bash

awk '
NR == 1 {
    R = $1
    next
}

NR <= R + 1 {
    position = NR - 1
    order[position] = $1
    required_version[$1] = $3
    next
}

$4 == "READY" && ($1 in required_version) && $2 == required_version[$1] {
    key = $1 SUBSEP $3
    if (!(key in seen)) {
        seen[key] = 1
        ready_count[$1]++
    }
}

END {
    missing = 0
    for (i = 1; i <= R; i++) {
        id = order[i]
        if (ready_count[id] < 3) {
            print id
            missing = 1
        }
    }
    if (!missing) {
        print "none"
    }
}
'

复杂度分析

时间复杂度为 $O(R+C)$,每条计划和日志只处理一次。

空间复杂度为 $O(R+K)$,其中 $K$ 是通过过滤的不同“资源包—平台”组合数,且 $K\le3R$。

易错点

  • FAIL 后出现同平台 READY 时,该平台仍应视为就绪。
  • 同一平台的多条 READY 只能计数一次。
  • 必须先判断 ($1 in required_version),再访问要求版本,避免把计划外资源误纳入统计。
  • 不能直接遍历 awk 关联数组输出,否则无法保证资源计划中的原始顺序。
  • 版本必须完全匹配,其他版本即使三个平台都 READY 也无效。

知识点总结

  • 值域约束经常可以推导出枚举维度的常数上界。看到 $\lvert a_i\rvert\le100$ 和目标值 $L^2$ 时,应立即比较区间最大和 $100L$ 与目标值。
  • 前缀和负责将定长区间求和降到 $O(1)$,长度剪枝负责将总复杂度从平方级降到线性级常数倍。
  • awk 适合处理按行组织的结构化文本:普通数组保存输出顺序,关联数组完成映射、集合和去重。
  • 运维开发类笔试不仅考算法,也会直接考 Shell、日志过滤和文本处理能力。