【题目】
CSP-J 2019 入门级 第一轮(初赛) 阅读程序(3)
#include <iostream>
using namespace std;
const int maxn = 10000;
int n;
int a[maxn];
int b[maxn];
int f(int l, int r, int depth) {
if (l > r)
return 0;
int min = maxn, mink;
for (int i = l; i <= r; ++i) {
if (min > a[i]) {
min = a[i];
mink = i;
}
}
int lres = f(l, mink - 1, depth + 1);
int rres = f(mink + 1, r, depth + 1);
return lres + rres + depth * b[mink];
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i)
cin >> a[i];
for (int i = 0; i < n; ++i)
cin >> b[i];
cout << f(0, n - 1, 1) << endl;
return 0;
}
判断题
- 如果 a 数组有重复的数字,则程序运行时会发生错误。()
- 如果 b 数组全为 0,则输出为 0。()
选择题
3. 当n=100时,最坏情况下,与第 12 行的比较运算执行的次数最接近的是:()
A. 5000
B. 600
C. 6
D. 100
4. 当n=100时,最好情况下,与第12行的比较运算执行的次数最接近的是:()
A. 100
B. 6
C. 5000
D. 600
5. 当n=10时,若b数组满足,对任意0≤i<n,都有b[i]=i+1,那么输出最大为()。
A. 386
B. 383
C. 384
D. 385
6. 当n=100时,若b数组满足,对任意0≤i<n,都有b[i]=1,那么输出最小为()。
A. 582
B. 580
C. 579
D. 581
【题目考点】
1. 递归
2. 树
【解题思路】
int main() {
cin >> n;
for (int i = 0; i < n; ++i)
cin >> a[i];
for (int i = 0; i < n; ++i)
cin >> b[i];
cout << f(0, n - 1, 1) << endl;
return 0;
}
输入a、b数组,下标从0到n-1,调用递归函数f,传入区间左右端点,第三个参数是层数,起始层数为1。
int f(int l, int r, int depth) {
if (l > r)
return 0;
int min = maxn, mink;
for (int i = l; i <= r; ++i) {
if (min > a[i]) {
min = a[i];
mink = i;
}
}
int lres = f(l, mink - 1, depth + 1);
int rres = f(mink + 1, r, depth + 1);
return lres + rres + depth * b[mink];
}
函数参数是左右端点和深度。
l<=r时进行递归,l>r时结束递归,是递归出口。
i从l到r循环,求a数组的最小值min,最小值的下标mink。
整个区间分为[l, mink-1],[mink+1, r]两个区间,对两个区间进行递归调用,深度depth+1。
返回值为[l, mink-1]求出的值加[mink+1, r]求出的值加深度乘以b数组中mink位置的值。
该算法建立了一个树形结构,对于每个区间,选a数组中最小值为根结点,对最小值左侧和右侧区间分别用相同方式建树。函数的返回值为每个结点下标对应b数组中的值乘以深度的加和。
【答案及解析】
1. 如果 a 数组有重复的数字,则程序运行时会发生错误。()
答:F
如果有重复数字,求最小值时会认为区间第一个数字是最小值,程序不会有错误
2. 如果 b 数组全为 0,则输出为 0。()
答:T
最后结果是每个结点深度乘以b数组中的值加和,如果b数组的值都为0,那么结果一定为0。
3. 当n=100时,最坏情况下,与第 12 行的比较运算执行的次数最接近的是:()
A. 5000
B. 600
C. 6
D. 100
答:A
第12行是if (min > a[i])
,该语句进行比较的次数,就是a数组中元素被遍历到的次数。
最坏情况下,每次选出的最小值在区间的左端或右端,这样下一次面对的区间的长度是上一次面对的区间长度减1。
最开始面对的区间长度为n,因此区间中元素被遍历到的次数为:
n
+
(
n
−
1
)
+
(
n
−
2
)
+
.
.
.
+
1
=
(
1
+
n
)
n
/
2
n+(n-1)+(n-2)+...+1=(1+n)n/2
n+(n−1)+(n−2)+...+1=(1+n)n/2
将n=100代入,得
(
1
+
100
)
∗
100
/
2
=
5050
(1+100)*100/2=5050
(1+100)∗100/2=5050,A选项5000最接近该数值,选A。
4. 当n=100时,最好情况下,与第12行的比较运算执行的次数最接近的是:()
A. 100
B. 6
C. 5000
D. 600
答:D
第12行是if (min > a[i])
,该语句进行比较的次数,就是a数组中元素被遍历到的次数。
最好情况下,每次选出的最小值的位置在区间的中点,这样将整个区间分为两个子区间,遍历两个子区间的长度加和为n。两个子区间又分为4个子区间,4个子区间的长度加和为n,……
整个区间不断一分为二,直到每个区间长度为1,也就是在求n除以2多少次后为1,除的次数为
log
2
n
\log_2{n}
log2n,对于每次分治,所有子区间的长度加和都为n,因此对于数组中元素的总遍历次数近似为
n
log
2
n
n\log_2{n}
nlog2n。
将n=100代入,得到
100
∗
log
2
100
≈
100
∗
6
=
600
100*\log_2{100}\approx 100*6=600
100∗log2100≈100∗6=600,选D。
第3、4题可以使用类似分析“快速排序平均时间复杂度、最坏时间复杂度”的分析方法来分析。
5. 当n=10时,若b数组满足,对任意0≤i<n,都有b[i]=i+1,那么输出最大为()。
A. 386
B. 383
C. 384
D. 385
答:D
b数组中下标0到9位置的值分别为1到10
为了使结果最大,那么应该让第1层的值为1,第2层的值为2,。。。,第10层的值为10,结果为:
1
2
+
2
2
+
.
.
.
+
1
0
2
1^2+2^2+...+10^2
12+22+...+102,已知
1
2
+
2
2
+
.
.
.
+
n
2
=
n
(
n
+
1
)
(
2
n
+
1
)
/
6
1^2+2^2+...+n^2=n(n+1)(2n+1)/6
12+22+...+n2=n(n+1)(2n+1)/6
则
1
2
+
2
2
+
.
.
.
+
1
0
2
=
10
∗
11
∗
21
/
6
=
385
1^2+2^2+...+10^2=10*11*21/6=385
12+22+...+102=10∗11∗21/6=385,选D。(不会公式的话,硬算也是可以的。)
6. 当n=100时,若b数组满足,对任意0≤i<n,都有b[i]=1,那么输出最小为()。
A. 582
B. 580
C. 579
D. 581
答:B
b数组中下标0到99位置的值都为1,那么最后的结果为所有结点层数加和
使得层数尽量少。要想使层数尽量少,那么每次a数组最小值的下标应该在整个区间中点的位置
设
d
p
[
i
]
dp[i]
dp[i]表示长为i的区间根据题目要求构成的二叉树中,每结点层数加和的最小值。
对于长为i的区间,如果a数组最小值下标为区间的第x位置,则将其分为长为x-1和长为i-x两段区间,两段区间生成的树的结点层数加和分别为
d
p
[
x
−
1
]
dp[x-1]
dp[x−1]和
d
p
[
i
−
x
]
dp[i-x]
dp[i−x],而这两个树又要作为
第x位置元素的子树,树中所有结点的层数都要加1,再加上第x位置元素在第1层,所以
d
p
[
i
]
=
d
p
[
x
−
1
]
+
d
p
[
i
−
x
]
+
x
−
1
+
i
−
x
+
1
=
d
p
[
x
−
1
]
+
d
p
[
i
−
x
]
+
i
dp[i] = dp[x-1]+dp[i-x]+x-1+i-x+1=dp[x-1]+dp[i-x]+i
dp[i]=dp[x−1]+dp[i−x]+x−1+i−x+1=dp[x−1]+dp[i−x]+i。
对于长为100的区间,中点应该在第50个数字的位置,将整个区间分为长为49和长为50的区间。
d
p
[
100
]
=
d
p
[
49
]
+
d
p
[
50
]
+
100
dp[100] = dp[49]+dp[50]+100
dp[100]=dp[49]+dp[50]+100,
对于长为49的区间,中点在第25个数字的位置,将整个区间分为两个长为24的区间。
以下情况以此类推,不再赘述。
d
p
[
49
]
=
d
p
[
24
]
∗
2
+
49
dp[49] = dp[24]*2+49
dp[49]=dp[24]∗2+49
d
p
[
50
]
=
d
p
[
24
]
+
d
p
[
25
]
+
50
dp[50] = dp[24]+dp[25]+50
dp[50]=dp[24]+dp[25]+50
d
p
[
100
]
=
d
p
[
24
]
∗
3
+
d
p
[
25
]
+
199
dp[100] = dp[24]*3+dp[25]+199
dp[100]=dp[24]∗3+dp[25]+199
d
p
[
24
]
=
d
p
[
12
]
+
d
p
[
11
]
+
24
dp[24] = dp[12]+dp[11]+24
dp[24]=dp[12]+dp[11]+24
d
p
[
25
]
=
2
∗
d
p
[
12
]
+
25
dp[25]=2*dp[12]+25
dp[25]=2∗dp[12]+25
d
p
[
100
]
=
d
p
[
12
]
∗
5
+
d
p
[
11
]
∗
3
+
296
dp[100] = dp[12]*5+dp[11]*3+296
dp[100]=dp[12]∗5+dp[11]∗3+296
d
p
[
12
]
=
d
p
[
6
]
+
d
p
[
5
]
+
12
dp[12] = dp[6]+dp[5]+12
dp[12]=dp[6]+dp[5]+12
d
p
[
11
]
=
2
∗
d
p
[
5
]
+
11
dp[11]=2*dp[5]+11
dp[11]=2∗dp[5]+11
d
p
[
100
]
=
d
p
[
5
]
∗
11
+
d
p
[
6
]
∗
5
+
389
dp[100] = dp[5]*11+dp[6]*5+389
dp[100]=dp[5]∗11+dp[6]∗5+389
易知
d
p
[
1
]
=
1
,
d
p
[
2
]
=
3
,
d
p
[
3
]
=
5
dp[1]=1,dp[2]=3,dp[3]=5
dp[1]=1,dp[2]=3,dp[3]=5
d
p
[
6
]
=
d
p
[
2
]
+
d
p
[
3
]
+
6
=
14
dp[6]=dp[2]+dp[3]+6=14
dp[6]=dp[2]+dp[3]+6=14
d
p
[
5
]
=
2
∗
d
p
[
2
]
+
5
=
11
dp[5]=2*dp[2]+5=11
dp[5]=2∗dp[2]+5=11
d
p
[
100
]
=
11
∗
11
+
14
∗
5
+
389
=
580
dp[100] = 11*11+14*5+389=580
dp[100]=11∗11+14∗5+389=580,选B。