林老师 · 客观题题库 · CSP-J 学习卷 L22 · 查找与二分

CSP-J 学习卷 L22 · 查找与二分

入门级算法 · 二分查找全族 / 两种写法与写法族 / 错误分析 / 二分答案与经典题 / STL·谓词·实数
真题
复刻
试卷编号LEARN-J-22
题目总数118 题 · 207 分
试卷类型客观题
考生须知:
① 本卷共 7 大部分,合计 118 题 · 207 分,全部为客观题;
② 试卷右上角设有 「提交答卷」 与 「重置考试」 按钮,提交后系统自动判分并显示答题正确情况,请确认全部作答后再行提交;
③ 试卷不显示答案,提交后方可查看每题作答与正确答案的对照;
④ 答卷进度会保留在本地缓存中,刷新或再次打开仍可继续作答;
⑤ 本卷仅供学生练习使用;请勿用于其他用途;题面有问题请联系:i64coder@163.com。

判 分 报 告

0 / 207 分
0
答 对 · 得 0 分
0
答 错 · 失 0 分
当前筛选下没有题目
壹

查找基础与二分思想

12 计分点 · 每点 1 分
第 1 题 单选 未作答

有 nn 个元素的无序数组,用顺序查找找某个值(假定值一定存在),平均要比较多少次?

(1 分)
原创教学题 | 考点:顺序查找:平均比较次数 (n+1)/2
第 2 题 单选 未作答

顺序查找找 x,常见写法每轮循环都要检查 i <= n(防止下标越界)。有人把 x 先放到 a[n] 这个哨兵位,然后循环里只判断 a[i] != x,不再判断下标。请问为什么这样能省掉越界判断?

01int seqFind(int a[], int n, int x) {
02    a[n] = x;
03    int i = 0;
04    while (a[i] != x) i++;
05    return i;
06}

(1 分)
原创教学题 | 考点:顺序查找哨兵:省越界判断
第 3 题 单选 未作答

二分查找能正确工作、并达到 O(log⁡n)O(\log n) 时间的前提条件是什么?

(1 分)
原创教学题 | 考点:二分前提:有序 + 随机访问;复杂度 O(logn)
第 4 题 单选 未作答

有人想:把顺序查找改成「每次取中间位置比一比,比目标小就取右半边」。对无序数组这样做的后果是什么?

(1 分)
原创教学题 | 考点:无序时 mid 比较为何不能排除一半
第 5 题 单选 未作答

n=10n = 10 的有序数组只查一次,老师却建议用顺序查找而不是二分查找。为什么?

(1 分)
原创教学题 | 考点:顺序查找 vs 二分:小数据用顺序
第 6 题 单选 未作答

对 n=100n = 100 个有序元素做二分查找,最多要比较多少次?为什么不是 66 次?

(1 分)
原创教学题 | 考点:最多比较次数 ceil(log2 n):n=100 为 7
第 7 题 单选 未作答

对下列 nn 个有序元素做二分查找,最大比较次数依次是 n=1000n = 1000 和 n=106n = 10^6 时?

(1 分)
原创教学题 | 考点:比较次数表:n=1000 与 10^6
第 8 题 单选 未作答

下面哪个场景的核心思路属于「每次把搜索范围缩小一半」的二分思想?

(1 分)
原创教学题 | 考点:二分思想:每次排除一半的应用识别
第 9 题 单选 未作答

顺序查找数组 a[0..n-1] 找目标 x,三种需求分别要求「找到第一个匹配的下标」「只判断是否存在」「数一数有几个匹配」。下面哪种说法正确?

(1 分)
原创教学题 | 考点:顺序查找变体:返回口径三选
第 10 题 单选 未作答

有 n = 9 个元素的数组,用顺序查找找一个确定存在的值。最坏情况下比较几次?平均情况下比较几次?

01int seqFind(const int a[], int n, int x) {
02    for (int i = 0; i < n; i++)
03        if (a[i] == x) return i;
04    return -1;
05}

(1 分)
原创教学题 | 考点:顺序查找最坏与平均次数数值
第 11 题 单选 未作答

数组是无序的,而且只查这一次——判断某个值在不在,以后不再查它。老师建议用顺序查找而不是先排序再二分。为什么?

(1 分)
原创教学题 | 考点:只查一次时,无序数据顺序查找更优
第 12 题 单选 未作答

猜数游戏:心里想一个 1∼1001 \sim 100 的整数,对方每次问「比这个数大还是小」并如实回答。用「每次砍一半」的策略,最多猜几次必中?

(1 分)
原创教学题 | 考点:猜数游戏:1~100 最多猜几次
贰

闭区间写法精确查找

21 计分点 · 每点 1 分
第 13 题 单选 未作答

下面的二分查找,有人担心它会不会死循环:如果 a[mid] != x 一直不命中,循环会不会永远转下去?

01int findX(const int a[], int n, int x) {
02    int l = 0, r = n - 1;
03    while (l <= r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] == x) return mid;
06        else if (a[mid] < x) l = mid + 1;
07        else r = mid - 1;
08    }
09    return -1;
10}

(1 分)
原创教学题 | 考点:闭区间写法为什么不会死循环
第 14 题 单选 未作答

把上面代码里的 else r = mid - 1; 误写成 else r = mid;,对 a = {1, 3, 5, 7, 9}、x = 2 运行,为什么程序永远停不下来?

01int l = 0, r = n - 1;
02while (l <= r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] == x) return mid;
05    else if (a[mid] < x) l = mid + 1;
06    else r = mid - 1;
07}
08return -1;

(1 分)
原创教学题 | 考点:把 r = mid - 1 改成 r = mid 为什么死循环
第 15 题 单选 未作答

对「把 r = mid - 1 改成 r = mid」的错误代码,判断死循环的标准调试术是:手动模拟区间缩到只剩两个元素时是否还在收缩。用 a = {2, 4, 6, 8}、x = 3 追踪:当区间第一次变成 l = 1, r = 2(只剩 4 和 6 两个元素)后,下一轮会怎样?

01int l = 0, r = n - 1;
02while (l <= r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] == x) return mid;
05    else if (a[mid] < x) l = mid + 1;
06    else r = mid - 1;
07}
08return -1;

(1 分)
原创教学题 | 考点:两元素自查法:构造反例数据
第 16 题 单选 未作答

闭区间写法查不到 x 时,循环以 l == r + 1 结束。为什么此时 l 恰好是「第一个大于 x 的位置」?

01int l = 0, r = n - 1;
02while (l <= r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] == x) return mid;
05    else if (a[mid] < x) l = mid + 1;
06    else r = mid - 1;
07}
08return -1;

(1 分)
原创教学题 | 考点:结束状态 l = r + 1 是插入位置
第 17 题 单选 未作答

把闭区间写法的命中分支从 return mid 改成 l = mid + 1(找到后不返回,继续往右收缩),对 a = {3, 5, 7}、x = 5 运行会怎样?

01int l = 0, r = n - 1;
02while (l <= r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] == x) return mid;
05    else if (a[mid] < x) l = mid + 1;
06    else r = mid - 1;
07}
08return -1;

(1 分)
原创教学题 | 考点:找到后不 return 继续收缩会怎样
第 18 题 单选 未作答

把闭区间写法误写成:a[mid] < x 时执行 r = mid - 1,a[mid] > x 时执行 l = mid + 1(两个分支写反),对 a = {2, 4, 6, 8}、x = 6(存在)运行会怎样?

01int l = 0, r = n - 1;
02while (l <= r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] == x) return mid;
05    else if (a[mid] < x) l = mid + 1;
06    else r = mid - 1;
07}
08return -1;

(1 分)
原创教学题 | 考点:两个分支写反会怎样
第 19 题 单选 未作答

补全下面的二分查找:当 a[mid] < x 时,左边全部元素(包括 a[mid])都小于 x,都不可能命中,所以下一轮从 mid + 1 开始。

01int findX(const int a[], int n, int x) {
02    int l = 0, r = n - 1;
03    while (l <= r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] == x) return mid;
06        else if (a[mid] < x) l = ____;
07        else r = mid - 1;
08    }
09    return -1;
10}

(1 分)
原创教学题 | 考点:补全闭区间写法模板
第 20 题 单选 未作答

用闭区间写法对 a = {2, 4, 6, 8, 10} 查找 x = 7(不存在)。循环结束后,l 和 r 分别等于多少?l 是什么位置?

01int l = 0, r = n - 1;
02while (l <= r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] == x) return mid;
05    else if (a[mid] < x) l = mid + 1;
06    else r = mid - 1;
07}
08return -1;

(1 分)
原创教学题 | 考点:找不到时结束状态追踪
第 21 题 单选 未作答

递归版二分与迭代版二分,为什么它们在正确性上完全等价、速度也只差常数?

01
02int findX1(int a[], int n, int x) {
03    int l = 0, r = n - 1;
04    while (l <= r) {
05        int mid = l + (r - l) / 2;
06        if (a[mid] == x) return mid;
07        if (a[mid] < x) l = mid + 1;
08        else r = mid - 1;
09    }
10    return -1;
11}
12
13int findX2(int a[], int l, int r, int x) {
14    if (l > r) return -1;
15    int mid = l + (r - l) / 2;
16    if (a[mid] == x) return mid;
17    if (a[mid] < x) return findX2(a, mid + 1, r, x);
18    return findX2(a, l, mid - 1, x);
19}

(1 分)
原创教学题 | 考点:递归版与迭代版为什么等价
第 22 题 单选 未作答

关于递归版二分查找,下面哪种说法正确?

(1 分)
原创教学题 | 考点:递归二分出口与栈深
第 23 题 单选 未作答

「ans 记录版」找左边界:找到 a[mid] >= x 就把 ans = mid 记下来,再继续往左收缩,最后返回 ans。为什么 ans 初值要取 n 而不是 0?

01int lowerB2(const int a[], int n, int x) {
02    int ans = n;
03    int l = 0, r = n - 1;
04    while (l <= r) {
05        int mid = l + (r - l) / 2;
06        if (a[mid] >= x) { ans = mid; r = mid - 1; }
07        else l = mid + 1;
08    }
09    return ans;
10}

(1 分)
原创教学题 | 考点:ans 记录版:初值为什么取 n
第 24 题 单选 未作答

红蓝染色表述把二分想象成:左半元素染成满足条件的颜色,右半染成不满足的颜色。下面哪种说法正确?

(1 分)
原创教学题 | 考点:红蓝染色表述
第 25 题 单选 未作答

有人用位运算写 mid = (l & r) + ((l ^ r) >> 1)。这个表达式算出的结果等价于下面哪个?

01int mid = (l & r) + ((l ^ r) >> 1);
02

(1 分)
原创教学题 | 考点:位运算 mid 技巧
第 26 题 单选 未作答

运行下面的程序,输出多少?

01#include <iostream>
02using namespace std;
03int main() {
04    int a[5] = {1, 3, 5, 7, 9};
05    int n = 5, x = 6;
06    int ans = n;
07    int l = 0, r = n - 1;
08    while (l <= r) {
09        int mid = l + (r - l) / 2;
10        if (a[mid] >= x) { ans = mid; r = mid - 1; }
11        else l = mid + 1;
12    }
13    cout << ans << endl;
14    return 0;
15}

(1 分)
原创教学题 | 考点:ans 记录版追踪(左边界)
第 27 题 单选 未作答

用闭区间写法对 a = {2, 4, 6, 8, 10} 查找不存在的 x = 7。运行下面的代码,循环体里的比较(判断 a[mid] == x、<、> 的分支判断)一共执行了几次?

01int findX(const int a[], int n, int x) {
02    int l = 0, r = n - 1, cnt = 0;
03    while (l <= r) {
04        int mid = l + (r - l) / 2;
05        cnt++;
06        if (a[mid] == x) return mid;
07        else if (a[mid] < x) l = mid + 1;
08        else r = mid - 1;
09    }
10    return -1;
11}

(1 分)
原创教学题 | 考点:闭区间写法找不到时的比较次数
第 28 题 单选 未作答

用下面的递归版二分对 a = {1, 3, 5, 7, 9} 查找 x = 5,函数最终返回多少?递归了几层?

01int findX(int a[], int l, int r, int x) {
02    if (l > r) return -1;
03    int mid = l + (r - l) / 2;
04    if (a[mid] == x) return mid;
05    if (a[mid] < x) return findX(a, mid + 1, r, x);
06    return findX(a, l, mid - 1, x);
07}

(1 分)
原创教学题 | 考点:递归二分追踪:返回值
第 29~33 题 阅读程序 (共 5 分) 未作答

题目(洛谷 P2249):给出 nn 个单调不减(非降序)的整数,mm 次询问,每次给一个整数 x,输出 x 第一次出现的位置(从 1 开始编号);若不存在输出 -1。

本题数据:n = 10,数组为 a = {1, 2, 3, 3, 3, 5, 7, 9, 11, 13},询问 x = 3、x = 4、x = 13。

01#include <iostream>
02using namespace std;
03int a[15];
04int firstX(int x, int n) {
05    int l = 1, r = n, ans = -1;
06    while (l <= r) {
07        int mid = l + (r - l) / 2;
08        if (a[mid] == x) { ans = mid; r = mid - 1; }
09        else if (a[mid] < x) l = mid + 1;
10        else r = mid - 1;
11    }
12    return ans;
13}
14int main() {
15    int n = 10;
16    int q[3] = {3, 4, 13};
17    for (int i = 1; i <= n; i++) cin >> a[i];
18    for (int i = 0; i < 3; i++) cout << firstX(q[i], n) << endl;
19    return 0;
20}

29.

本题第一问:对 x = 3,程序输出多少?

(1 分)
30.

本题第二问:对 x = 4(数组中不存在),程序输出多少?

(1 分)
31.

本题第三问:为什么命中分支要写 r = mid - 1 继续向左,而不是直接 return mid?

(1 分)
32.

本题第四问:若把命中分支误改成直接 return mid,对 x = 3 程序会输出多少?

(1 分)
33.

本题第五问:对 x = 13(数组最后一个元素),下面哪种说法正确?

(1 分)
原创教学题 | 经典·P2249 查找(第一个等于 x)
叁

边界写法与左右区间

24 计分点 · 每点 1 分
第 34 题 单选 未作答

数组有序,元素可重复。下面关于「左边界」和「右边界」的说法,哪个正确?

(1 分)
原创教学题 | 考点:左边界与右边界的定义
第 35 题 单选 未作答

找「第一个大于等于 x 的下标」,代码是下面这样。为什么 a[mid] >= x 时要写 r = mid,而不是 r = mid - 1?

01int lowerB(const int a[], int n, int x) {
02    int l = 0, r = n;
03    while (l < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] >= x) r = mid;
06        else l = mid + 1;
07    }
08    return l;
09}

(1 分)
原创教学题 | 考点:左边界为什么用 r = mid 不用 r = mid - 1
第 36 题 单选 未作答

求「最大可行值」的代码写成下面这样。为什么 lo 和 hi 只剩两个相邻整数时,mid 必须向上取整,否则死循环?

01int maxOK(int lo, int hi) {
02    while (lo < hi) {
03        int mid = lo + (hi - lo) / 2;
04        if (check(mid)) lo = mid;
05        else hi = mid - 1;
06    }
07    return lo;
08}

(1 分)
原创教学题 | 考点:l = mid 版为什么必须上取整
第 37 题 单选 未作答

求「最小可行值」的代码,把 mid 误写成上取整。为什么当 lo 和 hi 相邻时会死循环?

01int minOK(int lo, int hi) {
02    while (lo < hi) {
03        int mid = lo + (hi - lo + 1) / 2;
04        if (check(mid)) hi = mid;
05        else lo = mid + 1;
06    }
07    return lo;
08}

(1 分)
原创教学题 | 考点:r = mid 版为什么必须下取整
第 38 题 单选 未作答

左边界写法 while (l < r) 结束时,为什么一定满足 l == r,而且这个共同的值就是所求边界?

01int lowerB(const int a[], int n, int x) {
02    int l = 0, r = n;
03    while (l < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] >= x) r = mid;
06        else l = mid + 1;
07    }
08    return l;
09}

(1 分)
原创教学题 | 考点:边界写法结束为什么 l == r
第 39 题 单选 未作答

找「最后一个小于等于 x 的下标」,常见做法是:先找第一个大于 x 的位置,再减 1。为什么不直接二分「最后一个小于等于 x」?

01int upperB(const int a[], int n, int x) {
02    int l = 0, r = n;
03    while (l < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] > x) r = mid;
06        else l = mid + 1;
07    }
08    return l;
09}

(1 分)
原创教学题 | 考点:右边界为什么用第一个大于 x 减一
第 40 题 单选 未作答

对 a = {1, 3, 5, 7} 调 lowerB(a, 4, 100)(找第一个大于等于 100 的下标)。返回值是 4。为什么说直接写 a[idx] 会越界?

01int l = 0, r = n;
02while (l < r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] >= x) r = mid;
05    else l = mid + 1;
06}
07return l;

(1 分)
原创教学题 | 考点:全小于 x 时 lower_bound 返回 n 越界
第 41 题 单选 未作答

第三种写法用 l = -1, r = n 的开区间,while (l + 1 < r)。为什么它不用纠结取整方向,天然不会死循环?

01int lowerB3(const int a[], int n, int x) {
02    int l = -1, r = n;
03    while (l + 1 < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] >= x) r = mid; else l = mid;
06    }
07    return r;
08}

(1 分)
原创教学题 | 考点:开区间悬空版为什么免疫取整纠结
第 42 题 单选 未作答

用开区间悬空版代码对 a = {2, 4, 6, 8}、x = 5 查找第一个大于等于 5 的下标,逐轮追踪:l、r 依次如何变化?最终返回多少?

01int l = -1, r = n;
02while (l + 1 < r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] >= x) r = mid;
05    else l = mid;
06}
07return r;

(1 分)
原创教学题 | 考点:开区间悬空版追踪
第 43~47 题 阅读程序 (共 5 分) 未作答

题目:给一个非降序数组,多次询问,每次输出第一个大于等于 x 的元素的下标(从 0 开始);若整个数组都小于 x,输出 n。

本题数据:n = 7,数组 a = {1, 3, 3, 3, 5, 5, 8},依次查询 x = 3、x = 4、x = 10、x = 0。

01int lowerB(const int a[], int n, int x) {
02    int l = 0, r = n;
03    while (l < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] >= x) r = mid;
06        else l = mid + 1;
07    }
08    return l;
09}

43.

本题第一问:查询 x = 3,函数返回多少?

(1 分)
44.

本题第二问:查询 x = 4,函数返回多少?

(1 分)
45.

本题第三问:为什么 a[mid] >= x 分支要 r = mid,而 < 分支要 l = mid + 1?

(1 分)
46.

本题第四问:查询 x = 10(大于所有元素),返回多少?这意味着什么?

(1 分)
47.

本题第五问:查询 x = 0(小于所有元素),函数返回多少?

(1 分)
原创教学题 | 经典·左边界(第一个 >= x)
第 48~52 题 阅读程序 (共 5 分) 未作答

题目:给一个非降序数组,多次询问,每次输出最后一个小于等于 x 的元素的下标(从 0 开始);若所有元素都大于 x,输出 -1。

本题数据:n = 7,数组 a = {1, 3, 3, 3, 5, 5, 8},依次查询 x = 3、x = 5、x = 8。

01int upperB(const int a[], int n, int x) {
02    int l = 0, r = n;
03    while (l < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] > x) r = mid;
06        else l = mid + 1;
07    }
08    return l;
09}
10int lastLE(const int a[], int n, int x) {
11    return upperB(a, n, x) - 1;
12}

48.

本题第一问:查询 x = 3,upperB 返回多少?lastLE 返回多少?

(1 分)
49.

本题第二问:为什么 upperB 里是 a[mid] > x 而不是 >= x?

(1 分)
50.

本题第三问:查询 x = 5,lastLE 返回多少?

(1 分)
51.

本题第四问:查询 x = 8(等于最大元素),lastLE 返回多少?

(1 分)
52.

本题第五问:用 upperB(x) - 1 求右边界,和直接二分「最后一个小于等于 x」相比,好处是什么?

(1 分)
原创教学题 | 经典·右边界(最后一个 <= x)
第 53 题 单选 未作答

用左边界模板 lowerB(第一个 >= x)和右边界模板 upperB(第一个 > x),对 a = {1, 2, 2, 2, 3, 4, 4, 5} 统计 x = 2 和 x = 4 的出现次数,ub - lb 分别是多少?

01int L = lowerB(a, n, x);
02int R = upperB(a, n, x);
03int cnt = R - L;

(1 分)
原创教学题 | 考点:出现次数:ub - lb 计数
第 54 题 单选 未作答

对 a = {1, 1, 1, 1}(全是 1),分别统计 x = 1 和 x = 0 的出现次数(用 ub - lb),结果是多少?

01int L = lowerB(a, n, x);
02int R = upperB(a, n, x);
03int cnt = R - L;

(1 分)
原创教学题 | 考点:出现次数边界:不存在 x 与全等 x
第 55 题 单选 未作答

a = {5, 2, 8, 2, 9},sort(a, a + 5) 后数组变成 {2, 2, 5, 8, 9}。此时 lower_bound(a, a + 5, 5) - a 是多少?lower_bound(a, a + 5, 7) - a 呢?

01int L = lowerB(a, n, x);
02int R = upperB(a, n, x);
03int cnt = R - L;

(1 分)
原创教学题 | 考点:排序后 lower_bound 的作用
第 56 题 单选 未作答

对 a = {5, 6, 7, 8} 调左边界模板 lowerB(a, 4, 3)(找第一个大于等于 3 的下标),返回多少?

01int l = 0, r = n;
02while (l < r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] >= x) r = mid;
05    else l = mid + 1;
06}
07return l;

(1 分)
原创教学题 | 考点:左边界:x 小于所有元素
第 57 题 单选 未作答

对无重复有序数组 a = {1, 3, 5, 7, 9} 找「最后一个小于等于 x = 5 的下标」(用「第一个大于 5 减一」),结果是多少?

01int l = 0, r = n;
02while (l < r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] <= x) l = mid + 1;
05    else r = mid;
06}
07return l;

(1 分)
原创教学题 | 考点:右边界:无重复数组上就是精确位置
肆

错误分析:写错会怎样、为什么、怎么修

12 计分点 · 每点 1 分
第 58 题 单选 未作答

如果数组长度接近 2e9,l 和 r 都接近 1e9,下面两行求 mid 的写法有什么区别?

01int mid1 = (l + r) / 2;
02int mid2 = l + (r - l) / 2;

(1 分)
原创教学题 | 考点:(l+r)/2 溢出与 l+(r-l)/2
第 59 题 单选 未作答

下面的二分代码有个 bug。用「两元素自查法」判断:区间缩到哪一步时开始不再收缩?

01int search(int a[], int n, int x) {
02    int l = 0, r = n - 1;
03    while (l < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] == x) return mid;
06        if (a[mid] < x) l = mid;
07        else r = mid - 1;
08    }
09    return -1;
10}

(1 分)
原创教学题 | 考点:两元素自查:写出反例数据
第 60 题 单选 未作答

实数二分求 2\sqrt{2} 的近似值,有人把精度写成了 while (r - l > 1e-15)。为什么这行代码可能死循环?

01double lo = 0, hi = 2;
02for (int i = 0; i < 100; i++) {
03    double mid = (lo + hi) / 2;
04    if (mid * mid < 2) lo = mid;
05    else hi = mid;
06}

(1 分)
原创教学题 | 考点:实数二分 eps 过小的死循环
第 61 题 单选 未作答

「钢条切割(成本版)」:一根长 LL 的钢条,每切一刀的费用 = 这一刀时钢条的当前长度,求把钢条切成若干小段的最小总费用。最优解依赖切割顺序。有人想用二分答案求最小费用,为什么不行?

(1 分)
原创教学题 | 考点:check 不单调时二分给错答案
第 62 题 单选 未作答

二分答案「切 kk 段等长求最大段长」,段长范围取 lo = 1、hi = 5,但正确答案其实大于 5。会发生什么?

(1 分)
原创教学题 | 考点:初始 r 不盖答案域会怎样
第 63 题 单选 未作答

「砍树」问题(最大化伐木高度 h)中,check(h) 为真表示「得到木材够需求」。有人却按「最小可行」的模板写收缩方向。下面哪种说法正确?

(1 分)
原创教学题 | 考点:最大可行与最小可行方向写反
第 64 题 单选 未作答

把闭区间写法(while (l <= r),命中返回)改写成边界写法(while (l < r),不返回直接收缩到底),为什么要「三件套」整体改,只改循环条件行不行?

01
02int l = 0, r = n - 1;            int l = 0, r = n;
03while (l <= r) {                 while (l < r) {
04    int mid = l + (r - l) / 2;       int mid = l + (r - l) / 2;
05    if (a[mid] == x) return mid;     if (a[mid] >= x) r = mid;
06    else if (a[mid] < x) l = mid + 1;    else l = mid + 1;
07    else r = mid - 1;            }
08}                                return l;
09return -1;

(1 分)
原创教学题 | 考点:两种写法能否互相改写
第 65 题 单选 未作答

把标准升序二分代码直接拿来对降序数组查找 x,下面哪种说法正确?

(1 分)
原创教学题 | 考点:降序数组为什么三处全反
第 66 题 单选 未作答

为什么二分查找在链表上没法做到 O(log⁡n)O(\log n)?

(1 分)
原创教学题 | 考点:二分对链表不友好
第 67 题 单选 未作答

一个非降序数组在某个未知位置旋转(如 {4, 5, 6, 7, 0, 1, 2}),要在里面找最小值,二分思路为什么是「先判断哪一半有序」?

(1 分)
原创教学题 | 考点:旋转数组:先判断哪一半有序
第 68 题 单选 未作答

用「判断哪半有序」的二分对 a = {4, 5, 6, 7, 0, 1, 2} 找最小值(l=0, r=6,每次取 mid,若 a[mid] > a[r] 则 l = mid + 1 否则 r = mid),最后输出多少?

01int l = 0, r = n - 1;
02while (l < r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] > a[r]) l = mid + 1;
05    else r = mid;
06}
07return l;

(1 分)
原创教学题 | 考点:旋转数组找最小值追踪
第 69 题 单选 未作答

假设 int 上限是 2147483647(231−12^{31}-1)。若 l = 1500000000、r = 1800000000,下面哪种说法正确?

01int l = 1500000000, r = 1800000000;
02int bad  = (l + r) / 2;
03int good = l + (r - l) / 2;

(1 分)
原创教学题 | 考点:(l+r)/2 溢出数值验证
伍

二分答案与经典题

49 计分点 · 每点 1 分
第 70 题 单选 未作答

二分答案的本质是「如果候选值 x 可行,那么比它更宽松的候选值也一定可行」。为什么有了这条单调性,二分就能收敛到答案?

(1 分)
原创教学题 | 考点:二分答案为什么对:单调性论证
第 71 题 单选 未作答

「最大化最小值」和「最小化最大值」两类二分答案,check 的「难度方向」怎么确定?

(1 分)
原创教学题 | 考点:两大方向 check 方向怎么定
第 72 题 单选 未作答

「切木材」:若干根原木长度 LiL_i,要切出至少 k 段长度都为 x 的小段(余料丢弃),check 写成 sum(L[i] / x) >= k。为什么这个 check 是对的?x = 0 为什么必须特判?

01bool check(int x) {
02    int cnt = 0;
03    for (int i = 0; i < n; i++) cnt += L[i] / x;
04    return cnt >= k;
05}

(1 分)
原创教学题 | 考点:整除求和 check 为什么对、x=0 特判
第 73 题 单选 未作答

二分答案的题,check 的复杂度为什么必须控制在 O(n)O(n) 左右?整个算法总复杂度是多少?

(1 分)
原创教学题 | 考点:check 必须 O(n) 级、总复杂度 O(n log V)
第 74 题 单选 未作答

「切蛋糕」:nn 条蛋糕,长度分别为 a = {6, 8, 3, 5},要切出至少 k = 10 段等长蛋糕,每段长度是整数。求最大可能的段长。

先看边界数据:若 x = 3,四块蛋糕分别能切 6/3 = 2、8/3 = 2、3/3 = 1、5/3 = 1,共 6 段。那么下面哪种说法正确?

01bool check(int x) {
02    int cnt = 0;
03    for (int i = 0; i < n; i++) cnt += L[i] / x;
04    return cnt >= k;
05}

(1 分)
原创教学题 | 考点:切蛋糕边界:x 取下界/上界
第 75~79 题 阅读程序 (共 5 分) 未作答

题目:nn 条蛋糕,长度分别为 a = {6, 8, 3, 5},要把每条蛋糕切成等长小段(余料丢弃,不拼接),共得到至少 k = 10 段。每段长度必须是正整数。求能得到的最大段长。

01#include <iostream>
02using namespace std;
03int a[5] = {6, 8, 3, 5};
04int n = 4, k = 10;
05bool check(int x) {
06    int cnt = 0;
07    for (int i = 0; i < n; i++) cnt += a[i] / x;
08    return cnt >= k;
09}
10int main() {
11    int lo = 1, hi = 1000000;
12    while (lo < hi) {
13        int mid = lo + (hi - lo + 1) / 2;
14        if (check(mid)) lo = mid;
15        else hi = mid - 1;
16    }
17    cout << lo << endl;
18    return 0;
19}

75.

本题第一问:程序最终输出多少?(最大可行段长)

(1 分)
76.

本题第二问:为什么 mid 要写成上取整 lo + (hi - lo + 1) / 2?

(1 分)
77.

本题第三问:若把 hi 初始值改成 3,程序输出多少?

(1 分)
78.

本题第四问:若误把 check 的返回条件写成 cnt > k(严格大于)会怎样?

(1 分)
79.

本题第五问:若数组改成 a = {4, 4}、k = 2,程序输出多少?

(1 分)
原创教学题 | 经典·切蛋糕(最大化最小值入门)
第 80~84 题 阅读程序 (共 5 分) 未作答

题目(NOIP2015 跳石头):河道从起点(0 米)到终点(L 米)有若干块岩石,选手从起点跳到终点,必须踩在岩石上。组委会最多能移走 m 块岩石(起点终点的岩石不能移),求「最短跳跃距离」的最大值。

本题数据:L = 25,岩石位置(不含起点 0 和终点 25)为 a = {2, 11, 14, 17, 21}(n = 5),m = 2(最多移走 2 块)。

01#include <iostream>
02using namespace std;
03int L = 25, n = 5, m = 2;
04int a[6] = {0, 2, 11, 14, 17, 21};
05bool check(int d) {
06    int cnt = 0, last = 0;
07    for (int i = 1; i <= n; i++) {
08        if (a[i] - last < d) cnt++;
09        else last = a[i];
10    }
11    return cnt <= m;
12}
13int main() {
14    int lo = 1, hi = L;
15    while (lo < hi) {
16        int mid = lo + (hi - lo + 1) / 2;
17        if (check(mid)) lo = mid;
18        else hi = mid - 1;
19    }
20    cout << lo << endl;
21    return 0;
22}

80.

本题第一问:程序最终输出多少?

(1 分)
81.

本题第二问:check 里为什么是「a[i] - last < d 就挪走」这个贪心?

(1 分)
82.

本题第三问:为什么终点 L 不用放进 a[] 一起判断,但 check 最后要保证终点可达?

(1 分)
83.

本题第四问:若把 m 改成 1(只能挪 1 块),程序输出多少?

(1 分)
84.

本题第五问:若 last 初值误写成 a[0](即 last = 2),会怎样?

(1 分)
原创教学题 | 经典·跳石头(NOIP2015)
第 85~89 题 阅读程序 (共 5 分) 未作答

题目(牛棚放牛 / Aggressive cows):n 个牛棚位置(坐标),把 M 头奶牛放进棚里,任意两头牛的距离必须至少是 d。求最大可能的 d。

本题数据:牛棚位置 a = {1, 2, 8, 4, 9},排序后为 {1, 2, 4, 8, 9},n = 5,M = 3 头牛。

01#include <iostream>
02#include <algorithm>
03using namespace std;
04int a[6] = {1, 2, 8, 4, 9};
05int n = 5, M = 3;
06bool check(int d) {
07    int cnt = 1;
08    int last = a[0];
09    for (int i = 1; i < n; i++) {
10        if (a[i] - last >= d) {
11            cnt++;
12            last = a[i];
13        }
14    }
15    return cnt >= M;
16}
17int main() {
18    sort(a, a + n);
19    int lo = 1, hi = 1000000;
20    while (lo < hi) {
21        int mid = lo + (hi - lo + 1) / 2;
22        if (check(mid)) lo = mid;
23        else hi = mid - 1;
24    }
25    cout << lo << endl;
26    return 0;
27}

85.

本题第一问:程序最终输出多少?

(1 分)
86.

本题第二问:为什么 check 里第一头牛直接放在 a[0]?

(1 分)
87.

本题第三问:跳石头 check(a[i] - last < d 挪走)和本题 check(a[i] - last >= d 放下),两种写法什么关系?

(1 分)
88.

本题第四问:若把 check 里的 a[i] - last >= d 误写成 >,对 d = 3 结果如何?

(1 分)
89.

本题第五问:若牛棚位置改为 a = {1, 3, 5, 7, 9}、M = 3,输出多少?

(1 分)
原创教学题 | 经典·奶牛(放牛最大间距)
第 90~94 题 阅读程序 (共 5 分) 未作答

题目(洛谷 P1873 砍树):n 棵树,高度 HiH_i。把锯子设在一个高度 h,锯掉所有高于 h 的树冠,收集到木材的总量必须 ≥ need 立方米。求最大可能的 h。

本题数据:树高 a = {20, 15, 10, 17},n = 4,需求 need = 7 立方米。

01#include <iostream>
02using namespace std;
03int a[5] = {20, 15, 10, 17};
04int n = 4, need = 7;
05bool check(int h) {
06    long long tot = 0;
07    for (int i = 0; i < n; i++) {
08        if (a[i] > h) tot += a[i] - h;
09    }
10    return tot >= need;
11}
12int main() {
13    int lo = 1, hi = 1000000000;
14    while (lo < hi) {
15        int mid = lo + (hi - lo + 1) / 2;
16        if (check(mid)) lo = mid;
17        else hi = mid - 1;
18    }
19    cout << lo << endl;
20    return 0;
21}

90.

本题第一问:程序最终输出多少?

(1 分)
91.

本题第二问:check 随 h 怎么变化?这决定收缩方向吗?

(1 分)
92.

本题第三问:为什么 tot 要用 long long?

(1 分)
93.

本题第四问:若把 need 改成 3,输出多少?

(1 分)
94.

本题第五问:若把主循环误写成最小可行版(check(mid) 真时 hi = mid),need = 7 时输出多少?

(1 分)
原创教学题 | 经典·砍树(check 递减辨析)
第 95~99 题 阅读程序 (共 5 分) 未作答

题目(洛谷 P1182 数列分段):把 n 个正整数分成连续的若干段,段数不能超过 m 段,要求「最大段和」最小。求这个最小值。

本题数据:a = {4, 2, 4, 5, 1},n = 5,m = 3(最多 3 段)。

01#include <iostream>
02using namespace std;
03int a[6] = {4, 2, 4, 5, 1};
04int n = 5, m = 3;
05bool check(int x) {
06    int cnt = 1;
07    int cur = 0;
08    for (int i = 0; i < n; i++) {
09        if (cur + a[i] <= x) cur += a[i];
10        else { cnt++; cur = a[i]; }
11    }
12    return cnt <= m;
13}
14int main() {
15    int lo = 5, hi = 16;
16    while (lo < hi) {
17        int mid = lo + (hi - lo) / 2;
18        if (check(mid)) hi = mid;
19        else lo = mid + 1;
20    }
21    cout << lo << endl;
22    return 0;
23}

95.

本题第一问:程序最终输出多少?

(1 分)
96.

本题第二问:为什么答案区间下界取 lo = 5(最大单个元素)?

(1 分)
97.

本题第三问:为什么 mid 用下取整,且 check 真时 hi = mid?

(1 分)
98.

本题第四问:若把「不超过 mm 段」误写成「恰好 mm 段」的 check(cnt == m),会怎样?

(1 分)
99.

本题第五问:若数组改为 a = {1, 2, 3, 4, 5}、m = 2,输出多少?

(1 分)
原创教学题 | 经典·数列分段(最小化最大值)
第 100~104 题 阅读程序 (共 5 分) 未作答

题目:不排序,求 n 个数中第 k 小(从 1 开始计)的数。

本题数据:a = {5, 3, 7, 3, 9},n = 5,k = 3(第三小)。

01#include <iostream>
02using namespace std;
03int a[6] = {5, 3, 7, 3, 9};
04int n = 5, k = 3;
05int countLE(int x) {
06    int cnt = 0;
07    for (int i = 0; i < n; i++) if (a[i] <= x) cnt++;
08    return cnt;
09}
10int main() {
11    int lo = 1, hi = 100;
12    while (lo < hi) {
13        int mid = lo + (hi - lo) / 2;
14        if (countLE(mid) >= k) hi = mid;
15        else lo = mid + 1;
16    }
17    cout << lo << endl;
18    return 0;
19}

100.

本题第一问:程序最终输出多少?

(1 分)
101.

本题第二问:为什么第 k 小要在「值域」上二分而不是先排序再按下标二分?

(1 分)
102.

本题第三问:为什么 count(<=mid) >= k 时收缩 hi = mid?

(1 分)
103.

本题第四问:若数据改为 a = {10, 20, 30}、k = 2,值域改成 [1, 100],输出多少?

(1 分)
104.

本题第五问:这个「值域二分」与「二分查找在数组上找数」的本质区别是什么?

(1 分)
原创教学题 | 经典·第 k 小(值域二分)
第 105 题 单选 未作答

「跳石头」是移走岩石让最短跳跃距离最大;「路标设置」是加路标让最大空旷距离最小。为什么说它们是同一情境的镜像?

(1 分)
原创教学题 | 考点:跳石头与路标设置镜像
第 106 题 单选 未作答

牛棚位置 a = {1, 4, 8, 10, 14},用奶牛 check(cnt = 1, last = a[0],a[i] - last >= d 就放)检查 d = 4,最后 cnt 是多少?能放下 M = 3 头牛吗?

01int cnt = 1, last = a[0];
02for (int i = 1; i < n; i++)
03    if (a[i] - last >= d) { cnt++; last = a[i]; }
04return cnt >= M;

(1 分)
原创教学题 | 考点:奶牛 check 数值追踪
第 107 题 单选 未作答

路标设置:一条 L = 10 米的公路,起点 0、终点 10 处各有一个路标,中间已有 1 个路标在位置 3。最多可以再设 m = 2 个路标,要求「相邻路标的最大间距」尽量小。

用 check(x):若相邻间距 gap > x,就每隔 x 补一个路标。运行下面的程序,输出多少?

01#include <iostream>
02using namespace std;
03int pos[4] = {0, 3, 10};
04int n = 3, L = 10, m = 2;
05bool check(int x) {
06    int cnt = 0;
07    for (int i = 1; i < n; i++) {
08        int gap = pos[i] - pos[i - 1];
09        cnt += (gap - 1) / x;
10    }
11    return cnt <= m;
12}
13int main() {
14    int lo = 1, hi = L;
15    while (lo < hi) {
16        int mid = lo + (hi - lo) / 2;
17        if (check(mid)) hi = mid;
18        else lo = mid + 1;
19    }
20    cout << lo << endl;
21    return 0;
22}

(1 分)
原创教学题 | 考点:变式:路标设置(镜像)
第 108 题 单选 未作答

「月度开销」是数列分段的双胞胎:把 nn 天每天的花费 a[i] 分成连续的 m 个月(月),使「开销最大的月」最小。数据:a = {1, 2, 3, 4, 5}、n = 5、m = 3。

套用数列分段的 check(cnt 个月,段和 ≤ x),最大月开销最小为多少?

01bool check(int x) {
02    int cnt = 1; long long cur = 0;
03    for (int i = 0; i < n; i++) {
04        if (cur + a[i] <= x) cur += a[i];
05        else { cnt++; cur = a[i]; }
06    }
07    return cnt <= m;
08}

(1 分)
原创教学题 | 考点:变式:月度开销(数列分段双胞胎)
第 109 题 单选 未作答

「抄书/书本分配」:n 本书每本页数 a[i],按顺序分给 k 个人,每人至少一本、连续分配,求「抄书页数最多的人」最少是多少页。数据:a = {10, 20, 30, 40}、n = 4、k = 2。

用「最大页数和 ≤ x」的 check,最小化最大页数,答案是多少?

01bool check(int x) {
02    int cnt = 1; long long cur = 0;
03    for (int i = 0; i < n; i++) {
04        if (cur + a[i] <= x) cur += a[i];
05        else { cnt++; cur = a[i]; }
06    }
07    return cnt <= m;
08}

(1 分)
原创教学题 | 考点:变式:书本分配(连续段分割双胞胎)
第 110 题 单选 未作答

木材加工厂有 n = 4 根原木,长度 a = {10, 7, 8, 4},要切出至少 k = 6 段长度相等的木材(余料丢弃)。用「每根 floor(a[i]/x) 段」的 check,求最大段长。

(背景换成木材,模型和切蛋糕完全一样。)

01bool check(int x) {
02    int cnt = 0;
03    for (int i = 0; i < n; i++) cnt += L[i] / x;
04    return cnt >= k;
05}

(1 分)
原创教学题 | 考点:切木头与切蛋糕双胞胎(同模型换背景)
第 111 题 单选 未作答

复印店要把一份长文档按页连续分给 k = 3 个复印员,每份页数为 a = {7, 2, 5, 10, 8}(共 5 份),求「页数最多的那份」最少是多少页?(每人至少分到连续的一份)

01bool check(int x) {
02    int cnt = 1; long long cur = 0;
03    for (int i = 0; i < n; i++) {
04        if (cur + a[i] <= x) cur += a[i];
05        else { cnt++; cur = a[i]; }
06    }
07    return cnt <= m;
08}

(1 分)
原创教学题 | 考点:变式:抄书书稿复印(连续段变体)
第 112~116 题 阅读程序 (共 5 分) 未作答

题目(钢条等长切段):工厂有 n 根钢条,长度分别为 a = {9, 8, 7, 6, 5} 米。要把它们切成若干等长的小段(余料丢弃、不能拼接),一共要得到至少 k = 5 段。求最大可能的段长。

01#include <iostream>
02using namespace std;
03int a[6] = {9, 8, 7, 6, 5};
04int n = 5, k = 5;
05bool check(int x) {
06    int cnt = 0;
07    for (int i = 0; i < n; i++) cnt += a[i] / x;
08    return cnt >= k;
09}
10int main() {
11    int lo = 1, hi = 9;
12    while (lo < hi) {
13        int mid = lo + (hi - lo + 1) / 2;
14        if (check(mid)) lo = mid;
15        else hi = mid - 1;
16    }
17    cout << lo << endl;
18    return 0;
19}

112.

本题第一问:程序最终输出多少?

(1 分)
113.

本题第二问:为什么第二步答案域取 [1, 9] 而不是 [1, 100]?

(1 分)
114.

本题第三问:check 里用 a[i] / x 整除,9 / 5 = 1,为什么不是 1.8?

(1 分)
115.

本题第四问:若把 k 改成 8,程序输出多少?

(1 分)
116.

本题第五问:若把主循环误写成最小可行版(check(mid) 真时 hi = mid),k = 5 时输出多少?

(1 分)
原创教学题 | 经典·钢条等长切段(三步法)
第 117 题 单选 未作答

下面的跳石头 check 有个 bug:它把 a[n] 当成了最后一块岩石,循环里检查了 a[i] - last 后结束,却没有单独检查最后一段(终点到 last)的距离。

01bool check(int d) {
02    int cnt = 0, last = 0;
03    for (int i = 1; i <= n; i++) {
04        if (a[i] - last < d) cnt++;
05        else last = a[i];
06    }
07    return cnt <= m;
08}

(1 分)
原创教学题 | 考点:跳石头找错:check 漏判终点
第 118 题 单选 未作答

切蛋糕要求「切出至少 k 段」,check 写 cnt >= k。为什么改成「恰好 k 段」(cnt == k)答案不变?

01bool check(int x) {
02    int cnt = 0;
03    for (int i = 0; i < n; i++) cnt += L[i] / x;
04    return cnt >= k;
05}

(1 分)
原创教学题 | 考点:至少 k 段与恰好 k 段答案相同
陆

STL 三件套、谓词二分与实数

32 计分点 · 每点 1 分
第 119 题 单选 未作答

数组已升序排序,下面关于 C++ STL 三个二分函数的说法,哪个正确?

(1 分)
原创教学题 | 考点:STL 三件套语义
第 120 题 单选 未作答

为什么 lower_bound 返回「第一个大于等于 x」,而 upper_bound 返回「第一个大于 x」,一个带等号一个不带?

(1 分)
原创教学题 | 考点:lower_bound 与 upper_bound 为什么差一
第 121 题 单选 未作答

下面关于 lower_bound / upper_bound 返回值的说法,哪个正确?

(1 分)
原创教学题 | 考点:STL 进阶:迭代器与 end()
第 122 题 单选 未作答

对空数组 v 调 lower_bound(v.begin(), v.end(), 5),返回 v.end()。为什么不能写 *it 访问?

(1 分)
原创教学题 | 考点:end() 为什么不能解引用
第 123 题 单选 未作答

运行下面的程序,输出多少?

01#include <iostream>
02#include <algorithm>
03using namespace std;
04int main() {
05    int a[7] = {1, 2, 2, 2, 3, 3, 4};
06    int x = 2;
07    int L = lower_bound(a, a + 7, x) - a;
08    int R = upper_bound(a, a + 7, x) - a;
09    cout << L << "  " << R << "  " << R - L << endl;
10    return 0;
11}

(1 分)
原创教学题 | 考点:出现次数 = upper_bound - lower_bound
第 124 题 单选 未作答

a = {1, 3, 5, 7},要在有序数组里插入 x = 4 且保持有序,应该插在哪个位置?(下标从 0 开始)

01int l = 0, r = n;
02while (l < r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] >= x) r = mid;
05    else l = mid + 1;
06}
07return l;

(1 分)
原创教学题 | 考点:插入位置 = lower_bound
第 125 题 单选 未作答

有人说「质数在数列里的位置可以用二分找」。数组 a = {4, 6, 9, 10, 2, 3, 5, 7}(前四个非质数、后四个质数),下面哪种说法正确?

01int l = 0, r = n;
02while (l < r) {
03    int mid = l + (r - l) / 2;
04    if (isPrime(a[mid])) r = mid;
05    else l = mid + 1;
06}
07return l;

(1 分)
原创教学题 | 考点:找第一个质数何时能二分
第 126 题 单选 未作答

运行下面的程序,输出多少?

01#include <iostream>
02using namespace std;
03bool isPrime(int x) {
04    if (x < 2) return false;
05    for (int i = 2; i * i <= x; i++)
06        if (x % i == 0) return false;
07    return true;
08}
09int main() {
10    int a[8] = {4, 6, 9, 10, 2, 3, 5, 7};
11    int n = 8;
12    int l = 0, r = n;
13    while (l < r) {
14        int mid = l + (r - l) / 2;
15        if (isPrime(a[mid])) r = mid;
16        else l = mid + 1;
17    }
18    cout << l << endl;
19    return 0;
20}

(1 分)
原创教学题 | 考点:谓词二分追踪(第一个质数)
第 127 题 单选 未作答

「二分的本质」是什么?下面哪种说法最准确?

(1 分)
原创教学题 | 考点:谓词二分泛化:数值有序只是特例
第 128~132 题 阅读程序 (共 5 分) 未作答

题目(洛谷 P1102 a-b 数对):给 n 个数和整数 C,统计有多少个数对 (i, j) 满足 a[i] - a[j] = C 且 i != j。

本题数据:a = {1, 5, 3, 4, 2},n = 5,C = 2。

01#include <iostream>
02#include <algorithm>
03using namespace std;
04int a[6] = {1, 5, 3, 4, 2};
05int n = 5, C = 2;
06int main() {
07    sort(a, a + n);
08    long long cnt = 0;
09    for (int i = 0; i < n; i++) {
10        int t = a[i] - C;
11        int L = lower_bound(a, a + n, t) - a;
12        int R = upper_bound(a, a + n, t) - a;
13        cnt += R - L;
14    }
15    cout << cnt << endl;
16    return 0;
17}

128.

本题第一问:程序最终输出多少?

(1 分)
129.

本题第二问:为什么对每个 a[i] 只要数 a[i] - C 的出现次数就够?

(1 分)
130.

本题第三问:若把 C 改成 0,程序输出多少?(注意题意要求 i != j)

(1 分)
131.

本题第四问:若数据改成 a = {1, 1, 2, 3, 3}、C = 2,程序输出多少?

(1 分)
132.

本题第五问:整个算法的时间复杂度是多少?

(1 分)
原创教学题 | 经典·a-b 数对
第 133~137 题 阅读程序 (共 5 分) 未作答

题目:用实数二分求一个非负数 x 的立方根,误差不超过 10−610^{-6}。

本题数据:x = 27 和 x = 2。

01#include <iostream>
02using namespace std;
03double cubeRoot(double x) {
04    double lo = 0, hi = x;
05    if (x < 1) hi = 1;
06    for (int i = 0; i < 100; i++) {
07        double mid = (lo + hi) / 2;
08        if (mid * mid * mid < x) lo = mid;
09        else hi = mid;
10    }
11    return lo;
12}
13int main() {
14    cout << cubeRoot(27.0) << endl;
15    cout << cubeRoot(2.0) << endl;
16    return 0;
17}

133.

本题第一问:cubeRoot(27.0) 输出多少?

(1 分)
134.

本题第二问:为什么推荐固定迭代 100 次,而不是 while (r - l > 1e-6)?

(1 分)
135.

本题第三问:初始区间 [0, 27],迭代 tt 轮后区间长度大约是多少?

(1 分)
136.

本题第四问:若把 mid^3 < x 误写成 mid^3 > x(比较方向写反),cubeRoot(27.0) 会输出什么?

(1 分)
137.

本题第五问:对 cubeRoot(2.0),程序输出大约是多少?

(1 分)
原创教学题 | 经典·立方根(实数二分)
第 138 题 单选 未作答

一元三次方程 x^3 - 3x + 1 = 0 在 [−10,10][-10, 10] 内可能有 3 个根。为什么不能直接对整个区间 [-10, 10] 做二分找根?

(1 分)
原创教学题 | 考点:三次方程为什么要先隔离根
第 139 题 单选 未作答

对 f(x) = x^3 - x - 2,已知 f(1) = -2 < 0、f(2) = 4 > 0,在区间 [1, 2] 内二分求根(每次取 mid = (lo + hi) / 2,f(mid) < 0 则 lo = mid,否则 hi = mid)。做 3 轮后,区间变成多少?

01double lo = 1, hi = 2;
02for (int i = 0; i < 100; i++) {
03    double mid = (lo + hi) / 2;
04    if (f(mid) < 0) lo = mid;
05    else hi = mid;
06}

(1 分)
原创教学题 | 考点:三次方程求根数值题
第 140 题 单选 未作答

二分查找的最大比较次数 ⌈log⁡2n⌉\lceil \log_2 n \rceil 在 n=2n = 2、44、1616 时分别是多少?

(1 分)
原创教学题 | 考点:比较次数表:n = 2/4/16
第 141 题 单选 未作答

「山脉数组」a 满足先递增后递减(如 {1, 3, 5, 4, 2}),要求峰值位置。为什么对 mid 和 mid + 1 比较就能二分排除一半?

01int peakIndex(int a[], int n) {
02    int l = 0, r = n - 1;
03    while (l < r) {
04        int mid = l + (r - l) / 2;
05        if (a[mid] < a[mid + 1]) l = mid + 1;
06        else r = mid;
07    }
08    return l;
09}

(1 分)
原创教学题 | 考点:山脉数组为什么能用二分找峰
第 142 题 单选 未作答

用上面的 peakIndex 代码对 a = {1, 2, 3, 4, 3, 1} 运行,函数返回多少?

01int l = 0, r = n - 1;
02while (l < r) {
03    int mid = l + (r - l) / 2;
04    if (a[mid] < a[mid + 1]) l = mid + 1;
05    else r = mid;
06}
07return l;

(1 分)
原创教学题 | 考点:山脉数组找峰追踪
第 143 题 单选 未作答

简化贷款模型:借 100 元,按年利率 r 复利两年,两年后要还 121 元。求年利率 r 使 100(1+r)^2 = 121。下面用实数二分求 r(r 在 [0, 1],pay = 100*(1+r)*(1+r),pay < 121 则 lo = r,否则 hi = r)。这个 r 大约是多少?

01double lo = 0, hi = 1;
02for (int i = 0; i < 100; i++) {
03    double mid = (lo + hi) / 2;
04    double pay = 100 * (1 + mid) * (1 + mid);
05    if (pay < 121) lo = mid;
06    else hi = mid;
07}

(1 分)
原创教学题 | 考点:银行贷款利率实数二分
第 144 题 单选 未作答

三分法(每次取两个三分点比较)用来求单峰函数的极值。为什么二分法不能直接用来找单峰函数的峰值?

(1 分)
原创教学题 | 考点:三分为什么要求单峰
第 145 题 单选 未作答

关于「三分」和「LIS 的二分优化」,下面哪种说法正确?

(1 分)
原创教学题 | 考点:三分与 LIS 的二分优化
第 146 题 单选 未作答

题目:5 根钢条长度分别为 a = {9, 8, 7, 6, 5},要把它们切成若干等长的小段(余料丢弃、不拼接),一共要得到至少 5 段。求最大可能的段长。

三步法:① 设计 check;② 定答案域;③ 套主循环。运行下面的程序,输出多少?

01#include <iostream>
02using namespace std;
03int a[6] = {9, 8, 7, 6, 5};
04int n = 5, k = 5;
05bool check(int x) {
06    int cnt = 0;
07    for (int i = 0; i < n; i++) cnt += a[i] / x;
08    return cnt >= k;
09}
10int main() {
11    int lo = 1, hi = 9;
12    while (lo < hi) {
13        int mid = lo + (hi - lo + 1) / 2;
14        if (check(mid)) lo = mid;
15        else hi = mid - 1;
16    }
17    cout << lo << endl;
18    return 0;
19}

(1 分)
原创教学题 | 考点:钢条等长切段:三步法
第 147 题 单选 未作答

数组 a = {9, 7, 5, 3, 1} 是降序的,要在里面找元素 3 是否存在。有人用 binary_search(a, a + 5, 3)(默认升序比较),得到的结果会怎样?

(1 分)
原创教学题 | 考点:降序数组的 STL 查找
第 148 题 单选 未作答

要求「最大的整数段长」和「精度 10−610^{-6} 的实数立方根」,分别该用哪种二分控制?

(1 分)
原创教学题 | 考点:整数二分与实数二分选型
第 149 题 单选 未作答

用实数二分在 [1, 2] 上求 2\sqrt{2}(mid^2 < 2 则 lo = mid,否则 hi = mid)。做 3 轮后,区间变成多少?

01double lo = 0, hi = 2;
02for (int i = 0; i < 100; i++) {
03    double mid = (lo + hi) / 2;
04    if (mid * mid < 2) lo = mid;
05    else hi = mid;
06}

(1 分)
原创教学题 | 考点:实数二分:sqrt(2) 迭代追踪
第 150 题 单选 未作答

用 cubeRoot 求 0.1250.125 的立方根。若代码里没有 if (x < 1) hi = 1 这句(直接 hi = x = 0.125),会发生什么?

01double lo = 0;
02double hi = (x < 1) ? 1 : x;
03for (int i = 0; i < 100; i++) {
04    double mid = (lo + hi) / 2;
05    if (mid * mid * mid <= x) lo = mid;
06    else hi = mid;
07}

(1 分)
原创教学题 | 考点:立方根 x < 1 的上界
柒

真题检验 · 历年真题(原样罗列)

16 道真题 | 每题 1 分
第 151 题 单选 未作答

设有 100100 个已排好序的数据元素,采用折半查找时,最大比较次数为( )。

(1 分)
CSP-J 2019 · 单选 第5题 | 知识点 查找与二分
第 152 题 单选 未作答

新学期开学了,小胖想减肥,健身教练给小胖制定了两个训练方案。方案一:每次连续跑 33 公里可以消耗 300300 千卡(耗时半小时);方案二:每次连续跑 55 公里可以消耗 600600 千卡(耗时 11 小时)。小胖每周周一到周四能抽出半小时跑步,周五到周日能抽出一小时跑步。另外,教练建议小胖每周最多跑 2121 公里,否则会损伤膝盖。请问如果小胖想严格执行教练的训练方案,并且不想损伤膝盖,每周最多通过跑步消耗多少千卡?( )

(1 分)
CSP-J 2019 · 单选 第11题 | 知识点 查找与二分
第 153~158 题 阅读程序 (共 6 分) 未作答

1  #include <iostream>
2  using namespace std;
3  const int maxn = 10000;
4  int n;
5  int a[maxn];
6  int b[maxn];
7  int f(int l, int r, int depth) {
8      if (l > r)
9          return 0;
10      int min = maxn, mink;
11      for (int i = l; i <= r; ++i) {
12          if (min > a[i]) {
13              min = a[i];
14              mink = i;
15          }
16      }
17      int lres = f(l, mink - 1, depth + 1);
18      int rres = f(mink + 1, r, depth + 1);
19      return lres + rres + depth * b[mink];
20  }
21  int main() {
22      cin >> n;
23      for (int i = 0; i < n; ++i)
24          cin >> a[i];
25      for (int i = 0; i < n; ++i)
26          cin >> b[i];
27      cout << f(0, n - 1, 1) << endl;
28      return 0;
29  }

153.

如果 a 数组有重复的数字,则程序运行时会发生错误。( )

(1 分)
154.

如果 b 数组全为 00,则输出为 00。( )

(1 分)
155.

当 n=100n=100 时,最坏情况下,与第 1212 行的比较运算执行的次数最接近的是( )。

(1 分)
156.

当 n=100n=100 时,最好情况下,与第 1212 行的比较运算执行的次数最接近的是( )。

(1 分)
157.

当 n=10n=10 时,若 b 数组满足对任意 0≤i<n0\le i<n 都有 b[i] = i + 1,那么输出最大为( )。

(1 分)
158.

当 n=100n=100 时,若 b 数组满足对任意 0≤i<n0\le i<n 都有 b[i] = 1,那么输出最小为( )。

(1 分)
CSP-J 2019 · 阅读程序 第28-28-33题 | 知识点 查找与二分
第 159~163 题 完善程序 (共 5 分) 未作答

(矩阵变幻)有一个奇幻的矩阵,在不停地变幻,其变幻方式为:数字 00 变成矩阵 [0001]\begin{bmatrix}0&0\\0&1\end{bmatrix},数字 11 变成矩阵 [1110]\begin{bmatrix}1&1\\1&0\end{bmatrix}。最初该矩阵只有一个元素 00,变幻 nn 次后,矩阵会变成什么样?

例如,矩阵最初为:[0]\begin{bmatrix}0\end{bmatrix};矩阵变幻 11 次后:[0001]\begin{bmatrix}0&0\\0&1\end{bmatrix};矩阵变幻 22 次后:[0000010100110110]\begin{bmatrix}0&0&0&0\\0&1&0&1\\0&0&1&1\\0&1&1&0\end{bmatrix}。

输入一行一个不超过 1010 的正整数 nn。输出变幻 nn 次后的矩阵。

试补全程序。

提示:

<< 表示二进制左移运算符,例如 (11)2(11)_2 << 2=(1100)22=(1100)_2;

而 ^ 表示二进制异或运算符,它将两个参与运算的数中的每个对应的二进制位一一进行比较,若两个二进制位相同,则运算结果的对应二进制位为 00,反之为 11。

1  #include <cstdio>
2  using namespace std;
3  int n;
4  const int max_size = 1 << 10;
5 
6  int res[max_size][max_size];
7 
8  void recursive(int x, int y, int n, int t) {
9      if (n == 0) {
10          res[x][y] = ①;
11          return;
12      }
13      int step = 1 << (n - 1);
14      recursive(②, n - 1, t);
15      recursive(x, y + step, n - 1, t);
16      recursive(x + step, y, n - 1, t);
17      recursive(③, n - 1, !t);
18  }
19 
20  int main() {
21      scanf("%d", &n);
22      recursive(0, 0, ④);
23      int size = ⑤;
24      for (int i = 0; i < size; ++i) {
25          for (int j = 0; j < size; ++j)
26              printf("%d", res[i][j]);
27          puts("");
28      }
29      return 0;
30  }

159.

①处应填( )。

(1 分)
160.

②处应填( )。

(1 分)
161.

③处应填( )。

(1 分)
162.

④处应填( )。

(1 分)
163.

⑤处应填( )。

(1 分)
CSP-J 2019 · 完善程序 第34-34-38题 | 知识点 查找与二分
第 164 题 单选 未作答

设 AA 是 nn 个实数的数组,考虑下面的递归算法:

XYZ(A[1..n])
1 if n = 1 then return A[1]
2 else temp ← XYZ(A[1..n-1])
3      if temp < A[n]
4          then return temp
5          else return A[n]

请问算法 XYZ 的输出是什么?( )

(1 分)
CSP-J 2020 · 单选 第6题 | 知识点 查找与二分
第 165~170 题 阅读程序 (共 6 分) 未作答

1  #include <algorithm>
2  #include <iostream>
3  using namespace std;
4 
5  int n;
6  int d[50][2];
7  int ans;
8 
9  void dfs(int n, int sum) {
10      if (n == 1) {
11          ans = max(sum, ans);
12          return;
13      }
14      for (int i = 1; i < n; ++i) {
15          int a = d[i - 1][0], b = d[i - 1][1];
16          int x = d[i][0], y = d[i][1];
17          d[i - 1][0] = a + x;
18          d[i - 1][1] = b + y;
19          for (int j = i; j < n - 1; ++j)
20              d[j][0] = d[j + 1][0], d[j][1] = d[j + 1][1];
21          int s = a + x + abs(b - y);
22          dfs(n - 1, sum + s);
23          for (int j = n - 1; j > i; --j)
24              d[j][0] = d[j - 1][0], d[j][1] = d[j - 1][1];
25          d[i - 1][0] = a, d[i - 1][1] = b;
26          d[i][0] = x, d[i][1] = y;
27      }
28  }
29 
30  int main() {
31      cin >> n;
32      for (int i = 0; i < n; ++i)
33          cin >> d[i][0];
34      for (int i = 0; i < n; ++i)
35          cin >> d[i][1];
36      ans = 0;
37      dfs(n, 0);
38      cout << ans << endl;
39      return 0;
40  }

假设输入的 nn 是不超过 5050 的正整数,d[i][0]、d[i][1] 都是不超过 1000010000 的正整数,完成下面的判断题和单选题。

165.

若输入 nn 为 00,此程序可能会死循环或发生运行错误。( )

(1 分)
166.

若输入 nn 为 2020,接下来的输入全为 00,则输出为 00。( )

(1 分)
167.

输出的数一定不小于输入的 d[i][0] 和 d[i][1] 的任意一个。( )

(1 分)
168.

若输入的 nn 为 2020,接下来的输入是 2020 个 99 和 2020 个 00,则输出为( )。

(1 分)
169.

若输入的 nn 为 3030,接下来的输入是 3030 个 00 和 3030 个 55,则输出为( )。

(1 分)
170.

若输入的 nn 为 1515,接下来的输入是 1515 到 11,以及 1515 到 11,则输出为( )。

(1 分)
CSP-J 2020 · 阅读程序 第28-28-33题 | 知识点 查找与二分
第 171~175 题 完善程序 (共 5 分) 未作答

(最小区间覆盖)给出 nn 个区间,第 ii 个区间的左右端点是 [ai,bi][a_i,b_i]。现在要在这些区间中选出若干个,使得区间 [0,m][0,m] 被所选区间的并覆盖(即每一个 0≤i≤m0\le i\le m 都在某个所选的区间中)。保证答案存在,求所选区间个数的最小值。

输入第一行包含两个整数 nn 和 mm(1≤n≤50001\le n\le5000,1≤m≤1091\le m\le10^9)。

接下来 nn 行,每行两个整数 aia_i、bib_i(0≤ai,bi≤m0\le a_i,b_i\le m)。

提示:使用贪心法解决这个问题。先用 Θ(n2)\Theta(n^2) 的时间复杂度排序,然后贪心选择这些区间。

试补全程序。

1  #include <iostream>
2 
3  using namespace std;
4 
5  const int MAXN = 5000;
6  int n, m;
7  struct segment { int a, b; } A[MAXN];
8 
9  void sort() // 排序
10  {
11      for (int i = 0; i < n; i++)
12          for (int j = 1; j < n; j++)
13              if (①)
14              {
15                  segment t = A[j];
16                  ②
17              }
18  }
19 
20  int main()
21  {
22      cin >> n >> m;
23      for (int i = 0; i < n; i++)
24          cin >> A[i].a >> A[i].b;
25      sort();
26      int p = 1;
27      for (int i = 1; i < n; i++)
28          if (③)
29              A[p++] = A[i];
30      n = p;
31      int ans = 0, r = 0;
32      int q = 0;
33      while (r < m)
34      {
35          while (④)
36              q++;
37          ⑤;
38          ans++;
39      }
40      cout << ans << endl;
41      return 0;
42  }

171.

①处应填( )。

(1 分)
172.

②处应填( )。

(1 分)
173.

③处应填( )。

(1 分)
174.

④处应填( )。

(1 分)
175.

⑤处应填( )。

(1 分)
CSP-J 2020 · 完善程序 第39-39-43题 | 知识点 查找与二分
第 176 题 单选 未作答

在数据压缩编码中的哈夫曼编码方法,在本质上是一种( )的策略。

(1 分)
CSP-J 2021 · 单选 第11题 | 知识点 查找与二分
第 177 题 单选 未作答

有四个人要从 AA 点坐一条船过河到 BB 点,船一开始在 AA 点。该船一次最多可坐两个人。已知这四个人中每个人独自坐船的过河时间分别为 11、22、44、88,且两个人坐船的过河时间为两人独自过河时间的较大者。则最短( )时间可以让四个人都过河到 BB 点(包括从 BB 点把船开回 AA 点的时间)。

(1 分)
CSP-J 2021 · 单选 第15题 | 知识点 查找与二分
第 178~182 题 完善程序 (共 5 分) 未作答

(矩形计数)平面上有 nn 个关键点,求有多少个四条边都和 x 轴或者 y 轴平行的矩形,满足四个顶点都是关键点。给出的关键点可能有重复,但完全重合的矩形只计一次。

试补全枚举算法。

1  #include <iostream>
2 
3  using namespace std;
4 
5  struct point {
6      int x, y, id;
7  };
8 
9  bool equals(point a, point b) {
10      return a.x == b.x && a.y == b.y;
11  }
12 
13  bool cmp(point a, point b) {
14      return ①;
15  }
16 
17  void sort(point A[], int n) {
18      for (int i = 0; i < n; i++)
19          for (int j = 1; j < n; j++)
20              if (cmp(A[j], A[j - 1])) {
21                  point t = A[j];
22                  A[j] = A[j - 1];
23                  A[j - 1] = t;
24              }
25  }
26 
27  int unique(point A[], int n) {
28      int t = 0;
29      for (int i = 0; i < n; i++)
30          if (②)
31              A[t++] = A[i];
32      return t;
33  }
34 
35  bool binary_search(point A[], int n, int x, int y) {
36      point p;
37      p.x = x;
38      p.y = y;
39      p.id = n;
40      int a = 0, b = n - 1;
41      while (a < b) {
42          int mid = ③;
43          if (④)
44              a = mid + 1;
45          else
46              b = mid;
47      }
48      return equals(A[a], p);
49  }
50 
51  const int MAXN = 1000;
52  point A[MAXN];
53 
54  int main() {
55      int n;
56      cin >> n;
57      for (int i = 0; i < n; i++) {
58          cin >> A[i].x >> A[i].y;
59          A[i].id = i;
60      }
61      sort(A, n);
62      n = unique(A, n);
63      int ans = 0;
64      for (int i = 0; i < n; i++)
65          for (int j = 0; j < n; j++)
66              if (⑤ && binary_search(A, n, A[i].x, A[j].y) && binary_search(A, n, A[j].x, A[i].y)) {
67                  ans++;
68              }
69      cout << ans << endl;
70      return 0;
71  }

178.

①处应填( )

(1 分)
179.

②处应填( )

(1 分)
180.

③处应填( )

(1 分)
181.

④处应填( )

(1 分)
182.

⑤处应填( )

(1 分)
CSP-J 2021 · 完善程序 第39-39-43题 | 知识点 查找与二分
第 183~189 题 阅读程序 (共 7 分) 未作答

1  #include <iostream>
2 
3  using namespace std;
4 
5  int n, k;
6 
7  int solve1()
8  {
9      int l = 0, r = n;
10      while (l <= r) {
11          int mid = (l + r) / 2;
12          if (mid * mid <= n) l = mid + 1;
13          else r = mid - 1;
14      }
15      return l - 1;
16  }
17 
18  double solve2(double x)
19  {
20      if (x == 0) return x;
21      for (int i = 0; i < k; i++)
22          x = (x + n / x) / 2;
23      return x;
24  }
25 
26  int main()
27  {
28      cin >> n >> k;
29      double ans = solve2(solve1());
30      cout << ans << ' ' << (ans * ans == n) << endl;
31      return 0;
32  }

假设 int 为 3232 位有符号整数类型,输入的 n 是不超过 4700047000 的自然数、k 是不超过 int 表示范围的自然数,

183.

该算法最准确的时间复杂度分析结果为 O(log⁡n+k)O(\log n+k)。( )

(1 分)
184.

当输入为 9801 1 时,输出的第一个数为 99。( )

(1 分)
185.

对于任意输入的 n,随着所输入 k 的增大,输出的第二个数会变成 1。( )

(1 分)
186.

该程序有存在缺陷。当输入的 n 过大时,第 1212 行的乘法有可能溢出,因此应当将 mid 强制转换为 6464 位整数再计算。( )

(1 分)
187.

当输入为 2 1 时,输出的第一个数最接近( )。

(1 分)
188.

当输入为 3 10 时,输出的第一个数最接近( )。

(1 分)
189.

当输入为 256 11 时,输出的第一个数( )。

(1 分)
CSP-J 2022 · 阅读程序 第28-28-34题 | 知识点 查找与二分
第 190~194 题 完善程序 (共 5 分) 未作答

试补全程序。

1  #include <iostream>
2  #include <vector>
3 
4  using namespace std;
5 
6  int find_missing(vector<int>& nums) {
7      int left = 0, right = nums.size() - 1;
8      while (left < right) {
9          int mid = left + (right - left) / 2;
10          if (nums[mid] == mid + ①) {
11              ②;
12          } else {
13              ③;
14          }
15      }
16      return ④;
17  }
18 
19  int main() {
20      int n;
21      cin >> n;
22      vector<int> nums(n);
23      for (int i = 0; i < n; i++) cin >> nums[i];
24      int missing_number = find_missing(nums);
25      if (missing_number == ⑤) {
26          cout << "Sequence is consecutive" << endl;
27      } else {
28          cout << "Missing number is " << missing_number << endl;
29      }
30      return 0;
31  }

190.

①处应填( )

(1 分)
191.

②处应填( )

(1 分)
192.

③处应填( )

(1 分)
193.

④处应填( )

(1 分)
194.

⑤处应填( )

(1 分)
CSP-J 2023 · 完善程序 第33-33-37题 | 知识点 查找与二分
第 195 题 单选 未作答

假设有序表中有 1000 个元素,则用二分法查找元素 X 最多需要比较( )次。

(1 分)
CSP-J 2024 · 单选 第9题 | 知识点 查找与二分
第 196 题 单选 未作答

已知 f[0]=1,f[1]=1f[0] = 1 , f[1] = 1,并且对于所有 n≥2n \geq 2 有 f[n]=(f[n−1]+f[n−2])%7f[n] = (f[n-1] + f[n-2]) \% 7。那么 f[2025]f[2025] 的值是多少?( )

(1 分)
CSP-J 2025 · 单选 第8题 | 知识点 查找与二分
第 197~202 题 阅读程序 (共 6 分) 未作答

1  #include <algorithm>
2  #include <cstdio>
3  #include <cstring>
4  #define ll long long
5 
6  int n, k;
7  int a[200007];
8  int ans[200007];
9 
10  int main() {
11      scanf("%d%d", &n, &k);
12      for (int i = 1; i <= n; ++i) {
13          scanf("%d", &a[i]);
14      }
15      std::sort(a + 1, a + n + 1);
16      n = std::unique(a + 1, a + n + 1) - a - 1;
17      for (int i = 1, j = 0; i <= n; ++i) {
18          for (; j < i && a[i] - a[j + 1] > k; ++j)
19          ;
20          ans[i] = ans[j] + 1;
21      }
22      printf("%d\n", ans[n]);
23      return 0;
24  }

197.

当输入为 3 1 3 2 1 时,输出结果为 22。( )

(1 分)
198.

假设输入的 n 为正整数,输出的答案一定满足 ≤n\le n 且 ≥1\ge 1。( )

(1 分)
199.

将第 1414 行的:

1  n = std::unique(a + 1, a + n + 1) - a - 1;

删除后,有可能出现与原本代码不同的输出结果。( )

(1 分)
200.

假设输入的 a 数组和 k 均为正整数,执行第 1818 行代码时,一定满足的条件 不包括( )。

(1 分)
201.

当输入为:n = 100, k = 2, a = {1, 2, ..., 100} 时,输出为( )。

(1 分)
202.

假设输入的 a 数组和 k 均为正整数,但 a 数组不一定有序,则若误删去第 1313 行的:

std::sort(a + 1, a + n + 1);

程序有可能出现的问题有( )。

(1 分)
CSP-J 2025 · 阅读程序 第22-22-27题 | 知识点 查找与二分
第 203~207 题 完善程序 (共 5 分) 未作答

(精明与糊涂)有 NN 个人,分为两类:

i) 精明人:永远能正确判断其他人是精明还是糊涂。

ii) 糊涂人:判断不可靠,会给出随机的判断。

已知精明人严格占据多数,即如果精明人有 kk 个,则满足 k>N2k > \frac{N}{2}。

你只能通过函数 query(i, j) 让第 ii 个人判断第 jj 个人:返回 true 表示判断结果为“精明人”;返回 false 表示判断结果为“糊涂人”。你的目标是,通过这些互相判断,找出至少一个百分之百能确定的精明人。同时,你无需关心 query(i, j) 的内部实现。

以下程序利用“精明人占多数”的优势。设想一个“消除”的过程,让人们互相判断并进行抵消。经过若干轮抵消后,最终留下的候选者必然属于多数派,即精明人。

例如,假设有三个人 00、11、22。如果 00 说 11 是糊涂人,而 11 也说 00 是糊涂人,则 00 和 11 至少有一个是糊涂人。程序将同时淘汰 00 和 11。由于三人里至少有两个精明人,我们确定 22 是精明人。试补全程序。

1  #include <iostream>
2  #include <vector>
3  using namespace std;
4 
5  int N;
6  bool query(int i, int j);
7 
8  int main() {
9      cin >> N;
10 
11      int candidate = 0;
12      int count = ___①___;
13 
14      for (int i = 1; i < N; ++i) {
15          if (___②___) {
16              candidate = i;
17              count = 1;
18          } else {
19              if (___③___) {
20                  ___④___;
21              } else {
22                  count++;
23              }
24          }
25      }
26 
27      cout << ___⑤___ << endl;
28      return 0;
29  }

203.

①处应填( )

(1 分)
204.

②处应填( )

(1 分)
205.

③处应填( )

(1 分)
206.

④处应填( )

(1 分)
207.

⑤处应填( )

(1 分)
CSP-J 2025 · 完善程序 第39-39-43题 | 知识点 查找与二分