2021年信奥赛C++提高组csp-s初赛真题及答案解析(阅读程序第2题)

第2题
cpp
01 #include <algorithm>
02 #include <iostream>
03 using namespace std;
04
05 int n, a[1005];
06
07 struct Node
08 {
09 int h, j, m, w;
10
11 Node(const int _h, const int _j, const int _m, const int _w):
12 h(_h), j(_j), m(_m), w(_w)
13 { }
14
15 Node operator+(const Node &o) const
16 {
17 return Node(
18 max(h, w + o.h),
19 max(max(j, o.j), m + o.h),
20 max(m + o.w, o.m),
21 w + o.w);
22 }
23 };
24
25 Node solve1(int h, int m)
26 {
27 if (h > m)
28 return Node(-1, -1, -1, -1);
29 if (h == m)
30 return Node(max(a[h], 0), max(a[h], 0), max(a[h], 0), a[h]);
31 int j = (h + m) >> 1;
32 return solve1(h, j) + solve1(j + 1, m);
33 }
34
35 int solve2(int h, int m)
36 {
37 if (h > m)
38 return -1;
39 if (h == m)
40 return max(a[h], 0);
41 int j = (h + m) >> 1;
42 int wh = 0, wm = 0;
43 int wht = 0, wmt = 0;
44 for (int i = j; i >= h; i--){
45 wht += a[i];
46 wh = max(wh, wht);
47 }
48 for (int i = j + 1; i <= m; i++){
49 wmt += a[i];
50 wm = max(wm, wmt);
51 }
52 return max(max(solve2(h, j), solve2(j + 1, m)), wh + wm);
53 }
54
55 int main()
56 {
57 cin >> n;
58 for (int i = 1; i <= n; i++) cin >> a[i];
59 cout << solve1(1, n).j << endl;
60 cout << solve2(1, n) << endl;
61 return 0;
62 }
假设输入的所有数的绝对值都不超过 1000 ,完成下面的判断题和单选题:
判断题
-
程序总是会正常执行并输出两行两个相等的数。( )
A. 正确 B. 错误
-
第 28 行与第 38 行分别有可能执行两次及以上。( )
A. 正确 B. 错误
-
当输入为
5 -10 11 -9 5 -7时,输出的第二行为7。( )A. 正确 B. 错误
单选题
solve1(1, n)的时间复杂度为( )。
A. O(logn)
B. O(n)
C. O(nlogn)
D. O( n 2 n^2 n2)solve2(1, n)的时间复杂度为( )。
A. O(logn)
B. O(n)
C. O(nlogn)
D. O( n 2 n^2 n2)- 当输入为
10 -3 2 10 0 -8 9 -4 -5 9 4时,输出的第一行为( )。
A.13
B.17
C.24
D.12
题目代码分析
程序包含两个分治函数 solve1 和 solve2,均用于求解允许空子段的最大子段和(即当所有元素为负时结果为 0)。
solve1采用经典的分治合并法,结构体Node存储区间的四个关键信息:前缀最大和(h) 、区间最大子段和(j) 、后缀最大和(m) 、区间总和(w) 。合并操作operator+可在 O(1) 内完成。solve2同样分治,但合并时通过两个循环分别求左半部分的最大后缀和 与右半部分的最大前缀和,合并代价与区间长度成正比。
判断题答案及解析
-
程序总是会正常执行并输出两行两个相等的数。
- 当 (n \ge 1) 时,两函数均递归计算最大子段和,结果相等且非负。
- 当 (n = 0) 时,
solve1(1,0)执行第 28 行返回Node(-1,-1,-1,-1),.j = -1;solve2(1,0)执行第 38 行返回-1。输出均为-1,仍相等。 - 程序无崩溃风险,递归深度仅 (\log n),数组范围安全。故总是输出两个相等的数 。
答案:A
-
第 28 行与第 38 行分别有可能执行两次及以上。
- 递归过程中,划分区间
j = (h+m)>>1保证左右子区间均非空(当h < m时,j ≥ h且j < m)。因此内部递归不会出现h > m的情况。 - 仅当初始调用
h > m(如n = 0)时,各执行一次 。不可能执行两次或以上。
答案:B
- 递归过程中,划分区间
-
当输入为
5 -10 11 -9 5 -7时,输出的第二行为7。- 数组:
-10, 11, -9, 5, -7。 - 最大子段和显然是单独元素
11(或11 -9 +5 = 7更小),故结果应为11。 - 第二行是
solve2的输出,应为11,而非7。
答案:B
- 数组:
单选题答案及解析
-
solve1(1, n)的时间复杂度- 递归式 (T(n) = 2T(n/2) + O(1)),合并操作为常数时间。由主定理,时间复杂度为 O(n) 。
答案:B
- 递归式 (T(n) = 2T(n/2) + O(1)),合并操作为常数时间。由主定理,时间复杂度为 O(n) 。
-
solve2(1, n)的时间复杂度- 递归式 (T(n) = 2T(n/2) + O(n))(两个循环各扫描半个区间),由主定理,时间复杂度为 O(n log n) 。
答案:C
- 递归式 (T(n) = 2T(n/2) + O(n))(两个循环各扫描半个区间),由主定理,时间复杂度为 O(n log n) 。
-
当输入为
10 -3 2 10 0 -8 9 -4 -5 9 4时,输出的第一行- 数组:
-3, 2, 10, 0, -8, 9, -4, -5, 9, 4。 - 枚举连续子段,最大和为
2 + 10 + 0 -8 + 9 -4 -5 + 9 + 4 = 17(下标 2~10)。 solve1(1,n).j即此最大子段和,结果为 17 。
答案:B
- 数组:
专栏推荐:信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新)
https://blog.csdn.net/weixin_66461496/category_13125089.html
各种学习资料,助力大家一站式学习和提升!!!
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"########## 一站式掌握信奥赛知识! ##########";
cout<<"############# 冲刺信奥赛拿奖! #############";
cout<<"###### 课程购买后永久学习,不受限制! ######";
return 0;
}
1、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html
2、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新)
https://blog.csdn.net/weixin_66461496/category_13125089.html
3、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html
4、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}