欢迎大家订阅我的专栏:算法题解:C++与Python实现!
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!
专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。
适合人群:
- 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
- 希望系统学习C++/Python编程的初学者
- 想要提升算法与编程能力的编程爱好者
附上汇总贴:历年CSP-S初赛真题解析 | 汇总-CSDN博客
#include <algorithm>
#include <cstdio>
#include <cstring>
bool flag[27];
int n;
int p[27];
int ans = 0;
void dfs(int k) {
if (k == n+1) {
++ans;
return;
}
for (int i=1; i<=n; ++i) {
if (flag[i]) continue;
if (k>1 && i == p[k-1] +1) continue;
p[k] = i;
flag[i] = true;
dfs(k+1);
flag[i] = false;
}
return;
}
int main() {
scanf("%d", &n);
dfs(1);
printf("%d\n", ans);
return 0;
}
第16题
当输入的n=3的时候,程序输出的答案为3。( )
A.正确
B.错误
【答案】:A
【解析】
不出现相邻位置数字连续(递增1)的排列有:132,213,321
第17题
在dfs函数运行过程中,k的取值会满足1≤k≤n+1。( )
A.正确
B.错误
【答案】:A
【解析】
在调用dfs(1)时,k的初值为1,随后不断通过递归加一变成 n+1后,到达递归出口不再继续加一。
第18题
删除第19行的"flag[i]=false;",对答案不会产生影响。( )
A.正确
B.错误
【答案】:B
【解析】
当枚举第k个位置选择放数字i时,通过flag[i]=true进行标记,防止数字 i 在后面的位置被再一次放上。而从i枚举到i+1后,原本放在位置k的数字i,它的标记需要撤销,才能保证后续能够正确地判断数字是否放置过。
第19题
当输入的n=4的时候,程序输出的答案为。( )
A.11
B.12
C.24
D.9
【答案】:A
【解析】
枚举出所有24种排列,排除掉不合法的情况即可。
第20题
如果因为某些问题,导致程序运行第25行的 dfs 函数之前,数组p的初值并不全为0,则对程序的影响是( )。
A.输出的答案比原答案要小
B.无法确定输出的答案
C.程序可能陷入死循环
D.没有影响
【答案】:D
【解析】
p[ ] 数组的主要功能是用于在第15行去判断是否出现连续数字,而p[k-1]的值会在之前的dfs(k-1)中会被重新赋值,原本存在的值不会造成任何影响。
【答案】D
第21题
假如删去第14行的"if(flag[i]) continue;",输入3,得到的输出答案是( )。
A.27
B.3
C.16
D.12
【答案】:
【解析】
去掉后无需保证每个数字i是否在之前放置过,若不考虑连续数字的限制,可以直接枚举出所有3^3=27种情况,然后去除掉不合法情况即可。
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
int cnt_broken = 0;
int cnt_check = 0;
int n, k;
inline bool check(int h) {
printf("now check:%d\n", h);
++cnt_check;
if (cnt_broken == 2) {
printf("You have no egg!\n");
return false;
}
if (h >= k) {
++cnt_broken;
return true;
} else {
return false;
}
}
inline bool assert_ans(int h) {
if (h == k) {
printf("You are Right using %d checks\n", cnt_check);
return true;
} else {
printf("Wrong answer!\n");
return false;
}
}
inline void guess1(int n) {
for (int i=1; i<=n; ++i) {
if (check(i)) {
assert_ans(i);
return;
}
}
}
inline void guess2(int n) {
int w = 0;
for (w=1; w * (w+1)/2<n; ++w)
;
for (int ti = w, nh = w;; --ti, nh += ti, nh = std::min(nh, n)) {
if (check(nh)) {
for (int j = nh - ti + 1; j < nh; ++j) {
if (check(j)) {
assert_ans(j);
return;
}
}
assert_ans(nh);
return;
}
}
}
int main() {
scanf("%d%d", &n, &k);
int t;
scanf("%d", &t);
if (t == 1) {
guess1(n);
} else {
guess2(n);
}
return 0;
}
第22题
当输入为"6 5 1"时,猜测次数为5;当输入"6 5 2"时,猜测次数为3。( )
A.正确
B.错误
【答案】:A
【解析】
guess1函数会从1开始逐层枚举并检验,当i=5时结束,猜测次数为5。 guess2函数则是先将6层楼分成了3块,每块分别有3,2,1层。首先猜测3没碎,然后猜测5碎了。然后使用第2个鸡蛋,从4开始继续猜测,没碎,5不用猜测了。总猜测次数是3次。
第23题
不管输入的n和k具体为多少,t=2时的猜测数总是小于等于t=1时的猜测数。( )
A.正确
B.错误
【答案】:B
【解析】
考虑k=1,n=2的边界情况。t=1时猜测次数为k=1;而t=2时会先猜测2再猜测1,共2次操作。
第24题
不管t=1或t=2,程序都一定会猜到正确结果。( )
A.正确
B.错误
【答案】:A
【解析】
通过程序的整体分析可以知道两个函数的具体功能,它们都不会让鸡蛋的破碎次数超过2次。
第25题
函数guess1在运行过程中,cnt broken的值最多为( )。
A.0
B.1
C.2
D.n
【解析】guess1函数是暴力枚举每层去检测,当i=k时,鸡蛋会发生唯――次破碎,同时也得到了答案,程序结束。
【答案】B
第26题
函数guess2在运行过程中,最多使用的猜测次数的量级为( )。
A. O ( n ) O(n) O(n)
B. O ( n 2 ) O(n^2) O(n2)
C. O ( n ) O(\sqrt n) O(n)
D. O ( l o g n ) O(log n) O(logn)
【答案】:C
【解析】
由w*(w-1)<n的条件可以知道,w的量级是 O ( n ) O(\sqrt n) O(n),它的含义是将n层楼分成了w个块。第43行for循环枚举每个块检查的时候,鸡蛋在其中一个块破碎后会马上进入到这个块去检查每一层。已知每块中的层数也是w的级别,因此总共的量级是 O ( n ) O(\sqrt n) O(n)
第27题
当输入的n=100的时候,代码中t=1和t=2分别需要的猜测次数最多分别为( )。
A.100,14
B.100,13
C.99,144
D.99,13
【答案】:A
【解析】
guess1的猜测次数与有关,k最大取到100。guess2 中会先将100层分为14,13,…,3,2,1等若干块。当k=14时,正好会将前14层楼各猜测一次。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#define ll long long
int n, m;
std::vector<int> k, p;
inline int mpow(int x, int k) {
int ans = 1;
for (; k; k = k >> 1, x = x * x) {
if (k & 1)
ans = ans * x;
}
return ans;
}
std::vector<int> ans1, ans2;
int cnt1, cnt2;
inline void dfs(std::vector<int>& ans, int& cnt, int l, int r, int v) {
if (l > r) {
++cnt;
ans.push_back(v);
return;
}
for (int i= ; ++i) {
dfs(ans, cnt, l+1, r, v+k[l]*mpow(i, p[l]));
}
return;
}
std::vector<int> cntans1;
int main() {
scanf("%d%d", &n, &m);
k.resize(n + 1);
p.resize(n + 1);
for (int i=1; i<=n; ++i) {
scanf("%d%d", &k[i], &p[i]);
}
dfs(ans1, cnt1, 1, n >> 1, 0);
dfs(ans2, cnt2, (n>>1) + 1, n, 0);
std::sort(ans1.begin(), ans1.end());
int newcnt1 = 1;
cntans1.push_back(1);
for (int i=1; i<cnt1; ++i) {
if (ans1[i] == ans1[newcnt1 - 1]) {
++cntans1[newcnt1 - 1];
} else {
ans1[newcnt1++] = ans1[i];
cntans1.push_back(1);
}
}
cnt1 = newcnt1;
std::sort(ans2.begin(), ans2.end());
int las = 0;
ll ans = 0;
for (int i=cnt2-1; i>=0; --i) {
for (; las<cnt1 && ans1[las] + ans2[i] < 0; ++las)
;
if (las<cnt1 && ans1[las] + ans2[i] == 0)
ans += cntans1[las];
}
printf("%lld\n", ans);
return 0;
}
第28题
删除第51行的"std::sort(ans2.begin(), ans2.end()); "后,代码输出的结果不会受到影响。( )
A.正确
B.错误
【答案】:B
【解析】
第54行使用的是尺取法,需要保证ans2[i]是从大到小枚举,否则las 没有单调性,无法从小到大查找 ans1。
第29题
假设计算过程中不发生溢出,函数mpow(x, k)的功能是求出 x^k 的取值。( )
A.正确
B.错误
【答案】:A
【解析】
mpow函数的功能是使用二分求快速幂。
第30题
代码中第39行到第50行的目的是为了将ans1数组进行"去重"操作。( )
A.正确
B.错误
【答案】:A
【解析】
ans2[i]对应的 ans1 可能不止一个,为了降低时间复杂度,只能预处理ans1 中所有相同的值。
第31题
当输入为"3 15 1 2 -1 2 1 2"时,输出结果为( )。
A.4
B.8
C.0
D.10
【答案】:B
【解析】
把输入代入进去,得到的式子是x²-y²+z²=0,其中1≤x,y,≤15,其中(x,z,y)就是勾股定理三元组,符合条件的只有(3,4,5),(4,3,5),(6,8,10),(8,6,10),(9,12,15),(12,9,15),(5,12,13),(12,5,13)共八组。
第32题
记程序结束前p数组元素的最大值为P,则该代码的时间复杂度是( )。
A. O ( n ) O(n) O(n)
B. O ( m n l o g m n ) O(m^nlogm^n) O(mnlogmn)
C. O ( m n / 2 l o g m n / 2 ) O(m^{n/2}logm^{n/2}) O(mn/2logmn/2)
D. O ( m n / 2 ( l o g m n / 2 + l o g P ) ) O(m^{n/2}(logm^{n/2}+logP)) O(mn/2(logmn/2+logP))
【答案】:D
【解析】
每次dfs会生成 m n / 2 m^{n/2} mn/2 个值,每次递归都要调用一次 mpow,一次快速幂的时间复杂度为 O ( l o g P ) O(logP) O(logP),但是 dfs 的时间复杂度主要看最后一层,因此 dfs 的总复杂度为 O ( m n / 2 × l o g P ) O(m^{n/2}\times logP) O(mn/2×logP)。
之后使用 sort 对 ans1、ans2 排序,时间复杂度为 O ( m n / 2 × l o g m n / 2 ) O(m^{n/2}\times logm^{n/2}) O(mn/2×logmn/2)。
之后的去重、尺取法均为线性算法,时间复杂度为 O ( m n / 2 ) O(m^{n/2}) O(mn/2)。
综上,因为不知道 P 和 m 谁更大,所以不能省略,整个程序的时间复杂度是 O ( m n / 2 ( l o g m n / 2 + l o g P ) ) O(m^{n/2}(logm^{n/2}+logP)) O(mn/2(logmn/2+logP))。
第33题
本题所求出的是( )。
A.满足 a , b , c ∈ [ 1 , m ] a,b,c \in [1,m] a,b,c∈[1,m] 的整数方程 a 3 + b 3 = c 3 a^3+b^3=c^3 a3+b3=c3 解的数量
B.满足 a , b , c ∈ [ 1 , m ] a,b,c \in [1,m] a,b,c∈[1,m] 的整数方程 a 2 + b 2 = c 2 a^2+b^2=c^2 a2+b2=c2 解的数量
C.满足 x i ∈ [ 0 , m ] xi\in [0,m] xi∈[0,m] 的整数方程 ∑ i = 1 n k i ⋅ x i p i = 0 \sum_{i=1}^nk_i\cdot x_i^{p_i}=0 ∑i=1nki⋅xipi=0 的解的数量
D.满足 x i ∈ [ 1 , m ] xi\in [1,m] xi∈[1,m] 的整数方程 ∑ i = 1 n k i ⋅ x i p i = 0 \sum_{i=1}^nk_i\cdot x_i^{p_i}=0 ∑i=1nki⋅xipi=0 的解的数量
【答案】:D
【解析】
根据第 37 行 dfs 的系数是 n>>1,可以确定未知数个数一定是n个。根据第24行 i 从 1 到 m 枚举,可以确定未知数的取值范围是1到m。
857

被折叠的 条评论
为什么被折叠?



