GESP2025年6月认证C++八级( 第三部分编程题(1)树上旅行)

参考程序:

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;  // 最大节点数
const int L = 18;       // 因为最多跳 2^17 ≈ 13w > 1e5,所以倍增表最多 18 层
int n, q;              // n个节点,q次询问
int h[N], nx[N];       // 邻接表:h[u]是u的儿子链表头,nx[i]是i的兄弟
int par[L][N];         // par[i][u]: u向上跳2^i步的祖先编号
int son[L][N];         // son[i][u]: u向下跳2^i步,沿最小编号儿子路径

// 构建倍增表
void dfs(int u) {
    // 计算向上跳的倍增表
    for (int i = 1; i < L; i++)
        par[i][u] = par[i - 1][par[i - 1][u]];

    // 初始化son[0][u]为自身
    son[0][u] = u;

    // 遍历u的所有儿子,找到编号最小的那个
    for (int i = h[u]; i; i = nx[i]) {
        dfs(i);  // 递归构建子树
        // 若当前u还没有设置下跳路径,或者i比原来的小,就更新
        if (son[0][u] == u || i < son[0][u])
            son[0][u] = i;
    }

    // 构建向下跳的倍增表
    for (int i = 1; i < L; i++)
        son[i][u] = son[i - 1][son[i - 1][u]];
}

// 跳路径:从u向上/下跳step步,go表示跳跃表(par或son)
int move(int go[L][N], int u, int step) {
    for (int i = 0; i < L; i++)
        if ((step >> i) & 1)  // step包含2^i
            u = go[i][u];
    return u;
}
int main() {
    scanf("%d%d", &n, &q);

    // 构建树结构
    for (int i = 2; i <= n; i++) {
        scanf("%d", &par[0][i]);        // 读入第i个点的父亲
        nx[i] = h[par[0][i]];           // 建立邻接表(链式前向星)
        h[par[0][i]] = i;
    }

    par[0][1] = 1;  // 根节点指向自己(防越界)

    dfs(1);  // 构建倍增数组(上跳和下跳)

    // 处理每次旅行
    while (q--) {
        int s, k;
        scanf("%d%d", &s, &k);  // 起点s,k步

        while (k--) {
            int a;
            scanf("%d", &a);   // 读入第a步操作

            if (a < 0)         // 向下走
                s = move(son, s, -a);
            else               // 向上走
                s = move(par, s, a);
        }

        printf("%d\n", s);  // 输出最终所在节点
    }

    return 0;
}

<think>好的,我现在需要处理用户关于GESP 20246月C++认证真题解析的请求。首先,用户提供了几个引用,其中引用[2]、[3]、[4]都涉及具体的问题和解析。我需要确认这些引用的内容是否足够覆盖用户的需求,或者是否需要更多的信息。 用户明确提到想寻找真题解析,特别是C++的。根据引用[2],提到了欧几里得算法的一个实现,而引用[3]是关于gcd函数的解析,正确答案是选项C。引用[4]则涉及素数筛法中的循环条件。这些可能都是真题中的题目。 接下来,我需要整理这些引用中的信息,按照用户的要求结构化回答。用户要求回答结构清晰,分步骤解决问题,并且引用标识要自然地放在段落末尾。同时,必须使用中文回答,数学表达式用$...$或$$...$$格式,确保LaTeX正确。 首先,要确认每个引用对应的题目和解析是否正确。例如,引用[3]中的gcd(24,36)的解析是否正确。根据步骤,第一次调用gcd(24,36),因为36%24=12≠0,所以进入递归gcd(24,12)。第二次调用时24%12=0,返回12,正确。答案C对应12,符合解析。 引用[4]中的选项A的循环条件是否正确。素数筛法中,通常需要遍历已有的素数,并且i*primes[j]不超过n。因此,选项A的循环条件是j < primes.size() && i * primes[j] <=n,这个是正确的,所以选项A的代码是正确的写法。 然后,用户可能需要更多的真题解析,但根据提供的引用,可能只有这三题的解析。需要检查是否有其他题目在引用中没有提到,但用户可能需要更多的信息。但根据现有引用,只能提供这三个问题的解析。 在生成相关问题部分,需要根据现有内容提出相关问题,比如关于欧几里得算法、递归分析、素数筛法的循环条件等。 最后,确保所有数学表达式正确。例如,在欧几里得算法的说明中,可能需要数学表达式表示最大公约数的计算,但引用中的例子没有涉及复杂公式,所以可能不需要。但如果有涉及,比如在素数筛法中,可能需要说明i*primes[j]的作用,这时候可以用$i \times \text{primes}[j]$这样的表达。 总结步骤: 1. 根据引用[2]、[3]、[4]整理对应的题目和解析。 2. 结构化回答,分题目解析,每个题目给出详细步骤。 3. 确保LaTeX格式正确,特别是数学表达式部分。 4. 生成相关问题,基于现有内容。 5. 正确添加引用标识。</think>### GESP 20246月C++认证真题解析 #### 题目1:欧几里得算法实现 **代码实现**: ```cpp int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } ``` **解析**: 此算法通过递归计算两个数的最大公约数(GCD)。当`b`为0时返回`a`,否则递归调用`gcd(b, a % b)`。例如,计算`gcd(24, 36)`时: 1. 初始调用`gcd(24, 36)`,因`b=36≠0`,转为`gcd(36, 24%36=24)`; 2. 第二次调用`gcd(36, 24)`,转为`gcd(24, 36%24=12)`; 3. 第三次调用`gcd(24, 12)`,此时`24%12=0`,返回`12`[^3]。 --- #### 题目2:素数筛法循环条件 **代码选项**: ```cpp A. for (int j = 0; j < primes.size() && i * primes[j] <= n; j++) ``` **解析**: 此循环用于埃拉托斯特尼筛法中标记合数。条件`j < primes.size()`确保不越界,`i * primes[j] <= n`确保标记的合数不超过范围`n`。例如,当`i`与已知素数`primes[j]`相乘时,若结果超过`n`则终止循环,避免无效计算[^4]。 --- #### 题目3:递归函数结果分析 **题目**: `gcd(24, 36)`的返回值是? **解析**: 通过递归计算: 1. `gcd(24, 36)` → `gcd(36, 24)` 2. `gcd(36, 24)` → `gcd(24, 12)` 3. `gcd(24, 12)` → `12`(因`24%12=0`) 最终答案为`12`(选项C)[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汉克老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值