大厂真题

百度算法岗 2026-09-10

本场考试概述

考试时间:2026年9月10日

考试岗位:算法岗

难度评级:中等

考点分析

  • 第一题:构造(简单)
  • 第二题:二分答案 + 贪心 + 差分(中等)
  • 第三题:数论(中等偏难)

建议策略

  • 第一题的区间只是干扰项,交替串 0101… 对任意偶数长度的区间都成立,读完 n 直接输出即可,别去逐个满足区间
  • 第二题看到”最小值最大化”就想二分答案,判定时从左往右补缺口、窗口起点尽量靠右,再用差分把单次判定压到线性
  • 第三题先证明”起点对 H 余数不同”就保证互不重叠,答案化成对每个 H 取 min(H, cnt) 的最大值;H 可能大于标记种数,不能只枚举到 c
  • 第二题的单个缺口可达 3 乘 10 的 9 次方,C++、Java、Go 要用 64 位整数

第 1 题:区间平衡01串构造

题目描述

给定一个正整数 数学公式(保留原始 SVG) 以及 数学公式(保留原始 SVG) 个区间,第 数学公式(保留原始 SVG) 个区间为 数学公式(保留原始 SVG),保证每个区间的长度 数学公式(保留原始 SVG) 都是偶数。

请构造一个长度为 数学公式(保留原始 SVG) 且仅由字符 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 组成的字符串 数学公式(保留原始 SVG)(下标从 数学公式(保留原始 SVG) 开始),使得对于每一个给定区间 数学公式(保留原始 SVG),子串 数学公式(保留原始 SVG) 中字符 数学公式(保留原始 SVG) 的个数与字符 数学公式(保留原始 SVG) 的个数相等。

可以证明在题目给定的范围内一定存在满足条件的字符串。如果存在多个满足条件的字符串,输出任意一个即可。

输入描述

第一行输入一个整数 数学公式(保留原始 SVG),表示字符串的长度。

第二行输入一个整数 数学公式(保留原始 SVG),表示区间的数量,保证 数学公式(保留原始 SVG) 为偶数。

此后 数学公式(保留原始 SVG) 行,第 数学公式(保留原始 SVG) 行输入两个整数 数学公式(保留原始 SVG),表示第 数学公式(保留原始 SVG) 个区间,保证 数学公式(保留原始 SVG) 为偶数。

输出描述

在一行上输出一个长度为 数学公式(保留原始 SVG) 的字符串,表示构造出的答案。

如果存在多个满足条件的字符串,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。

样例1

输入

7
4
1 4
2 7
3 6
5 6

输出

0101010

样例解释

构造的字符串为 数学公式(保留原始 SVG)。区间 数学公式(保留原始 SVG) 对应子串 数学公式(保留原始 SVG),区间 数学公式(保留原始 SVG) 对应子串 数学公式(保留原始 SVG),二者都含 数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG);区间 数学公式(保留原始 SVG) 对应子串 数学公式(保留原始 SVG),含 数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG);区间 数学公式(保留原始 SVG) 对应子串 数学公式(保留原始 SVG),含 数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG)。四个区间全部满足条件。

题解:构造

思路分析

给出若干个长度为偶数的区间,要构造一个 01 串,使每个区间内 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 的个数相等,多解任取其一。

这是一道看穿之后几乎没有代码的构造题:区间多达 数学公式(保留原始 SVG) 个且互相重叠,逐个去满足会互相牵制,关键是找到一个对所有偶数长度区间同时成立的串。

算法实现

先看交替串 数学公式(保留原始 SVG) 有什么性质。它任意相邻的两位,恰好是一个 数学公式(保留原始 SVG) 和一个 数学公式(保留原始 SVG)

对长度为偶数的区间 数学公式(保留原始 SVG),从 数学公式(保留原始 SVG) 开始每两位切一刀,正好切成 数学公式(保留原始 SVG) 对相邻位置,每对各贡献一个 数学公式(保留原始 SVG) 和一个 数学公式(保留原始 SVG),于是

数学公式(保留原始 SVG)

这里 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 分别是区间内 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 的个数。推导只用到了区间长度为偶数,与区间在哪、和别的区间怎样重叠都无关,所以交替串一次性满足全部 数学公式(保留原始 SVG) 个约束。

题面保证长度为偶数,正是这个构造成立的前提。反过来,只要混进一个长度为奇数的区间,数学公式(保留原始 SVG) 为奇数,任何串都不可能让两者相等。

实现上只需读入 数学公式(保留原始 SVG),从第 数学公式(保留原始 SVG) 位起奇数位放 数学公式(保留原始 SVG)、偶数位放 数学公式(保留原始 SVG),拼成字符串输出,区间数据不参与计算。以 数学公式(保留原始 SVG) 开头的 数学公式(保留原始 SVG) 同样合法,评测会逐个区间核验,两种都能通过。

复杂度分析

时间复杂度数学公式(保留原始 SVG)。逐位生成长度为 数学公式(保留原始 SVG) 的字符串是唯一开销,与区间个数 数学公式(保留原始 SVG) 无关。

空间复杂度数学公式(保留原始 SVG),存放待输出的字符串。

题解代码

import sys
input = sys.stdin.readline

def build(n):
    chars = []
    for i in range(n):
        chars.append('0' if i % 2 == 0 else '1')
    return ''.join(chars)

n = int(input())
print(build(n))

正确性说明

任意偶数长度区间都能分成相邻两位,每对在交替串中含一个零和一个一,故所有给定区间同时平衡。

易错点与边界

区间数量为偶数是题面给出的附加条件,构造本身只依赖每个区间长度为偶数。多解输出不必与样例逐字符一致。

第 2 题:定长区间加一最大化最小值

题目描述

给定一个长度为 数学公式(保留原始 SVG) 的整数数组 数学公式(保留原始 SVG),以及两个整数 数学公式(保留原始 SVG)数学公式(保留原始 SVG)

你可以进行至多 数学公式(保留原始 SVG) 次操作。每次操作选择一个整数 数学公式(保留原始 SVG),将 数学公式(保留原始 SVG) 这连续 数学公式(保留原始 SVG) 个元素各加上 数学公式(保留原始 SVG)。同一个位置 数学公式(保留原始 SVG) 可以被选择多次。

请求出在操作次数不超过 数学公式(保留原始 SVG) 的前提下,数组最小值 数学公式(保留原始 SVG) 能够达到的最大值。

输入描述

第一行输入三个整数 数学公式(保留原始 SVG),分别表示数组长度、每次操作覆盖的元素个数以及操作次数上限。

第二行输入 数学公式(保留原始 SVG) 个整数 数学公式(保留原始 SVG),表示数组元素。

输出描述

在一行上输出一个整数,表示数组最小值能够达到的最大值。

样例1

输入

5 3 4
2 5 3 6 1

输出

3

样例解释

每次操作覆盖连续 数学公式(保留原始 SVG) 个元素,最多操作 数学公式(保留原始 SVG) 次。

要让最小值达到 数学公式(保留原始 SVG):先选 数学公式(保留原始 SVG) 操作 数学公式(保留原始 SVG) 次,数组变为 数学公式(保留原始 SVG);此时 数学公式(保留原始 SVG) 还差 数学公式(保留原始 SVG),而能覆盖 数学公式(保留原始 SVG) 的只有 数学公式(保留原始 SVG),选它操作 数学公式(保留原始 SVG) 次,数组变为 数学公式(保留原始 SVG),最小值为 数学公式(保留原始 SVG),共用 数学公式(保留原始 SVG) 次操作。

要让最小值达到 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 需要 数学公式(保留原始 SVG) 操作 数学公式(保留原始 SVG) 次,数学公式(保留原始 SVG) 需要 数学公式(保留原始 SVG) 操作 数学公式(保留原始 SVG) 次,共需 数学公式(保留原始 SVG) 次,超过上限 数学公式(保留原始 SVG),无法做到。因此答案为 数学公式(保留原始 SVG)

题解:二分答案

思路分析

每次把一段长度固定为 数学公式(保留原始 SVG) 的连续区间整体加 数学公式(保留原始 SVG),最多做 数学公式(保留原始 SVG) 次,要让数组最小值尽可能大。

这是一道判定比求值容易的题:给定目标值问能否做到,从左往右补缺口就能回答,且可行性随目标值单调。

算法实现

二分答案:二分最终的最小值 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 能达到时,同一套操作对任何更小的目标也成立,满足二分的单调性。每次操作最多让最小值加 数学公式(保留原始 SVG),故答案落在 数学公式(保留原始 SVG) 内。

check 函数:给定 数学公式(保留原始 SVG),从左往右扫,维护当前位置已被叠加的量 数学公式(保留原始 SVG),位置 数学公式(保留原始 SVG) 的缺口为

数学公式(保留原始 SVG)

数学公式(保留原始 SVG),就以 数学公式(保留原始 SVG) 为起点补做 数学公式(保留原始 SVG) 次操作,累计次数超过 数学公式(保留原始 SVG) 立刻判不可行。

起点这样选是最优的。左边位置都已达标,缺口只能靠覆盖 数学公式(保留原始 SVG) 的窗口补;这些窗口里起点越靠右,盖住的右侧元素越多,把任何更靠左的起点换成它,后面的缺口只减不增。起点上限是 数学公式(保留原始 SVG),所以末尾 数学公式(保留原始 SVG) 个位置只能共用最后一个窗口。

朴素写法每补一次就把窗口内 数学公式(保留原始 SVG) 个元素逐个加上,单次 check 是 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 时远超时限。改用差分,在 数学公式(保留原始 SVG) 处记下这批加量到此失效,扫到那里时从 数学公式(保留原始 SVG) 里减掉,单次 check 降到 数学公式(保留原始 SVG)

数学公式(保留原始 SVG) 可达 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 低到 数学公式(保留原始 SVG),单个缺口就有 数学公式(保留原始 SVG),缺口与累计次数须用 数学公式(保留原始 SVG) 位整数。

二分过程:check 通过令 数学公式(保留原始 SVG),否则令 数学公式(保留原始 SVG)。中点取上中位数 数学公式(保留原始 SVG),否则 数学公式(保留原始 SVG) 且 check 通过时会死循环。

输出:区间收缩到 数学公式(保留原始 SVG) 时,数学公式(保留原始 SVG) 就是最小值能达到的最大值。

复杂度分析

时间复杂度:O(n log(k+2)),包含 k=0 时的输入和最小值扫描。

空间复杂度:O(n)。

题解代码

import sys
input = sys.stdin.readline

def check(a, n, w, k, target):
    expire = [0] * (n + 1)
    last = n - w  # 窗口起点(0 下标)最多只能到 n-w
    add = 0       # 当前位置被所有生效窗口加了多少
    used = 0      # 已经用掉的操作次数
    for i in range(n):
        add -= expire[i]
        need = target - a[i] - add
        if need > 0:
            used += need
            if used > k:
                return False
            add += need
            start = i if i < last else last
            expire[start + w] += need
    return True

def max_min_value(a, n, w, k):
    lo = min(a)
    hi = lo + k
    while lo < hi:
        mid = lo + (hi - lo + 1) // 2
        if check(a, n, w, k, mid):
            lo = mid
        else:
            hi = mid - 1
    return lo

n, w, k = map(int, input().split())
a = list(map(int, input().split()))
print(max_min_value(a, n, w, k))

正确性说明

从左向右处理首个不足目标的位置,任何方案都必须补足该缺口。把覆盖它的操作尽量右移,既不破坏已满足位置,又不减少对未来位置的覆盖,故贪心使用最少操作。差分只压缩相同的区间更新;单调判定上的二分得到最大可行目标。

易错点与边界

数组允许负数,k 可以为 0;末尾起点需要截到 n-w,不能创建越界窗口。

第 3 题:周期标记最多启用种数

题目描述

在一条向两端无限延伸的数轴上,整数点的下标取遍全体整数 数学公式(保留原始 SVG)。现有 数学公式(保留原始 SVG) 种标记,第 数学公式(保留原始 SVG) 种标记的周期为 数学公式(保留原始 SVG)

标记的规则如下:若某个整数点 数学公式(保留原始 SVG) 被打上第 数学公式(保留原始 SVG) 种标记,那么整数点 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 也必须打上第 数学公式(保留原始 SVG) 种标记,并且该规则会反复生效。也就是说,第 数学公式(保留原始 SVG) 种标记一旦从起点 数学公式(保留原始 SVG) 开始打,就会覆盖集合 数学公式(保留原始 SVG) 中的所有整数点。

你需要先选定一个正整数 数学公式(保留原始 SVG),然后从这 数学公式(保留原始 SVG) 种标记中挑选若干种启用,并为每种启用的标记指定一个起点,要求同时满足以下两个条件:

  1. 每种启用的标记,其周期 数学公式(保留原始 SVG) 必须是 数学公式(保留原始 SVG) 的倍数;
  2. 任意两种启用的标记,它们的起点对 数学公式(保留原始 SVG) 取模的结果互不相同。

每个整数点最多只能打上一种标记,允许存在不打任何标记的整数点。请求出启用的标记种数最多是多少。

输入描述

每个测试文件包含多组测试数据。第一行输入一个整数 数学公式(保留原始 SVG),表示数据组数,每组测试数据描述如下:

在一行上先输入一个整数 数学公式(保留原始 SVG),表示标记的种数,紧接着在同一行输入 数学公式(保留原始 SVG) 个整数 数学公式(保留原始 SVG),表示每种标记的周期。

保证所有测试数据的 数学公式(保留原始 SVG) 之和不超过 数学公式(保留原始 SVG)

输出描述

在一行上输出 数学公式(保留原始 SVG) 个整数,相邻两个整数之间用一个空格分隔,第 数学公式(保留原始 SVG) 个整数表示第 数学公式(保留原始 SVG) 组测试数据中启用的标记种数的最大值。

样例1

输入

3
5 6 10 15 30 7
4 2 2 2 2
3 5 7 11

输出

3 2 1

样例解释

第一组数据取 数学公式(保留原始 SVG),周期是 数学公式(保留原始 SVG) 的倍数的标记为 数学公式(保留原始 SVG),共 数学公式(保留原始 SVG) 种,而对 数学公式(保留原始 SVG) 取模有 数学公式(保留原始 SVG) 种不同结果,足够让它们的起点互不相同,因此可以启用 数学公式(保留原始 SVG) 种。取 数学公式(保留原始 SVG) 同样能启用 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 种,而任何 数学公式(保留原始 SVG) 都无法启用 数学公式(保留原始 SVG) 种,答案为 数学公式(保留原始 SVG)

第二组数据取 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 种标记的周期都是 数学公式(保留原始 SVG) 的倍数,但对 数学公式(保留原始 SVG) 取模只有 数学公式(保留原始 SVG) 种不同结果,所以最多启用 数学公式(保留原始 SVG) 种,答案为 数学公式(保留原始 SVG)

第三组数据中周期 数学公式(保留原始 SVG) 两两没有大于 数学公式(保留原始 SVG) 的公约数,任何 数学公式(保留原始 SVG) 至多只能启用 数学公式(保留原始 SVG) 种,取 数学公式(保留原始 SVG) 时对 数学公式(保留原始 SVG) 取模只有 数学公式(保留原始 SVG) 种结果,答案为 数学公式(保留原始 SVG)

题解:数论

思路分析

给定 数学公式(保留原始 SVG) 个周期,选一个 数学公式(保留原始 SVG),只能启用周期是 数学公式(保留原始 SVG) 倍数的标记,且起点对 数学公式(保留原始 SVG) 的余数互不相同,求最多启用几种。

这是一道先化简条件、再解决计数效率的数论题:看清不重叠限制自动成立后,答案是一个最值式,难点变成快速统计每个 数学公式(保留原始 SVG) 的倍数个数。

算法实现

先看不重叠这条限制。两种标记覆盖的点集 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 有公共点,当且仅当 数学公式(保留原始 SVG),其中 数学公式(保留原始 SVG)。若 数学公式(保留原始 SVG) 都是 数学公式(保留原始 SVG) 的倍数,则 数学公式(保留原始 SVG),起点对 数学公式(保留原始 SVG) 余数不同就推出对 数学公式(保留原始 SVG) 余数也不同,两者必然不相交。

于是固定 数学公式(保留原始 SVG) 后,能用的标记有 数学公式(保留原始 SVG) 种,可用的余数只有 数学公式(保留原始 SVG) 种,把起点依次取 数学公式(保留原始 SVG) 就能取满较小的那个:

数学公式(保留原始 SVG)

朴素做法对每个 数学公式(保留原始 SVG) 扫一遍全部周期,单组就是 数学公式(保留原始 SVG) 次。

改为从周期出发去数。数学公式(保留原始 SVG) 不是任何 数学公式(保留原始 SVG) 的约数时 数学公式(保留原始 SVG),不影响答案;反过来从每个 数学公式(保留原始 SVG) 出发,给它的每个约数各记一次,就恰好得到全部非零的 数学公式(保留原始 SVG)。总工作量是 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 以内的数约数最多 数学公式(保留原始 SVG) 个,最坏约 数学公式(保留原始 SVG) 次加法。

注意 数学公式(保留原始 SVG) 不能只枚举到 数学公式(保留原始 SVG)。周期为 数学公式(保留原始 SVG) 时取 数学公式(保留原始 SVG) 能启用 数学公式(保留原始 SVG) 种,而 数学公式(保留原始 SVG) 都只能启用 数学公式(保留原始 SVG) 种,只看 数学公式(保留原始 SVG) 会得到错误答案 数学公式(保留原始 SVG)

算法实现上分三步:

第一步,用调和级数 筛预处理约数表:对每个 数学公式(保留原始 SVG),把它追加到 数学公式(保留原始 SVG) 的约数表里。

第二步,每组先按值去重得到重数 数学公式(保留原始 SVG),对每个不同的值 数学公式(保留原始 SVG),给它约数表里的每个 数学公式(保留原始 SVG) 执行 数学公式(保留原始 SVG)。C++、Java、Go 用数组计数,处理完一组只清零本组碰过的下标;若每组都清空整个数组,数学公式(保留原始 SVG) 时就是 数学公式(保留原始 SVG) 次清零。

第三步,遍历本组出现过的 数学公式(保留原始 SVG),取 数学公式(保留原始 SVG) 的最大值作为该组答案。

复杂度分析

时间复杂度:O(M log(M+1)+S+∑τ(v)),S 为全部周期输入数;求和按各组不同周期 v 计,τ 为约数个数。

空间复杂度:O(M log(M+1)+S),包含约数表及全部输入组。

题解代码

import sys
input = sys.stdin.readline

from collections import Counter
from itertools import chain

def build_divisors(limit):
    divs = [[] for _ in range(limit + 1)]
    for d in range(1, limit + 1):
        for j in range(d, limit + 1, d):
            divs[j].append(d)
    return divs

def max_enabled(ps, divs):
    freq = Counter(ps)
    cnt = Counter(chain.from_iterable(map(divs.getitem, freq)))
    for v, f in freq.items():
        if f > 1:
            for d in divs[v]:
                cnt[d] += f - 1
    return max(map(min, cnt.keys(), cnt.values()))

t = int(input())
groups = []
for _ in range(t):
    nums = list(map(int, input().split()))
    groups.append(nums[1:])

limit = max(max(g) for g in groups)
divs = build_divisors(limit)
print(' '.join(str(max_enabled(g, divs)) for g in groups))

正确性说明

固定 H 后只有整除 H 的周期可选,且最多使用 H 个不同余数。取互异起点余数可使各标记集合不相交,因此上界 min(H,cnt) 可以达到。枚举所有实际出现的周期约数覆盖一切可能有正贡献的 H,取最大值正确。

易错点与边界

H 可以大于标记种数,例如两个周期均为 5。复杂度需包含全部输入组占用,不能只写约数表的空间。

小结

优先从题面约束提炼模型,再用样例检查边界。本文保留题面数学符号的原始 SVG,代码统一为 Python 3;未给出的评测限制或规则不补作事实。