1

GESP认证C++编程真题解析 | 202403 八级

​欢迎大家订阅我的专栏:算法题解:C++与Python实现
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!

专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。

适合人群:

  • 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
  • 希望系统学习C++/Python编程的初学者
  • 想要提升算法与编程能力的编程爱好者

附上汇总帖:GESP认证C++编程真题解析 | 汇总


编程题

P10263 公倍数问题

【题目来源】

洛谷:[P10263 GESP202403 八级] 公倍数问题 - 洛谷

【题目描述】

小 A 写了一个 \(N \times M\) 的矩阵 \(A\),我们看不到这个矩阵,但我们可以知道,其中第 \(i\) 行第 \(j\) 列的元素 \(A_{i,j}\)\(i\)\(j\) 的公倍数(\(i=1,\dots,N\)\(j=1,\dots,M\))。现在有 \(K\) 个小朋友,其中第 \(k\) 个小朋友想知道,矩阵 \(A\) 中最多有多少个元素可以是 \(k\)\(k=1,2,\dots,K\))。请你帮助这些小朋友求解。

注意:每位小朋友的答案互不相关,例如,有些位置既可能是 \(x\),又可能是 \(y\),则它同时可以满足 \(x,y\) 两名小朋友的要求。

方便起见,你只需要输出 \(\sum_{k=1}^{K}{k \times \texttt{ans}_k}\) 即可,其中 \(\texttt{ans}_k\) 表示第 \(k\) 名小朋友感兴趣的答案。

【输入】

第一行三个正整数 \(N,M,K\)

【输出】

输出一行,即 \(\sum_{k=1}^{K}{k \times \texttt{ans}_k}\)

请注意,这个数可能很大,使用 C++ 语言的选手请酌情使用 long long 等数据类型存储答案。

【输入样例】

2 5 2

【输出样例】

9

【算法标签】

《洛谷 P10263 公倍数问题》 #数学# #调和级数# #GESP# #2024#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

#define int long long  // 定义int为long long类型
int n, m, k, ans;      // n: 行数, m: 列数, k: 遍历范围, ans: 答案
int a[1000005], b[1000005];  // a: 存储1~1000000的因数个数(针对n), b: 存储1~1000000的因数个数(针对m)

// 预处理函数:计算1~1000000的因数个数
// divisor[]: 存储结果的数组
// n: 实际需要计算的最大值
void count_divisor(int n, int divisor[])
{
    // 类似埃氏筛法计算每个数的因数个数
    for (int i = 1; i <= n; i++)  // i是可能的因数
    {
        // 将i的倍数都增加1,因为i是这些数的因数
        for (int j = i; j <= 1000000; j += i)
        {
            divisor[j] += 1;  // j的因数个数加1
        }
    }
}

signed main()  // 因为#define int long long,所以用signed main
{
    // 输入n, m, k
    cin >> n >> m >> k;
    
    // 预处理计算因数个数
    // a[i]: 表示在1~n范围内,i的因数个数
    // b[i]: 表示在1~m范围内,i的因数个数
    count_divisor(n, a);
    count_divisor(m, b);
    
    // 计算答案
    for (int i = 1; i <= k; i++)  // 遍历1到k
    {
        // 计算公式:ans = Σ(i=1 to k) [i * a[i] * b[i]]
        ans += i * a[i] * b[i];
        
        // 调试输出
        // cout << "ans " << ans << endl;
    }
    
    // 输出结果
    cout << ans << endl;
    
    return 0;
}

【运行结果】

2 5 2
9

P10264 接竹竿

【题目来源】

洛谷:[P10264 GESP202403 八级] 接竹竿 - 洛谷

【题目描述】

小杨同学想用卡牌玩一种叫做“接竹竿”的游戏。

游戏规则是:每张牌上有一个点数 \(v\),将给定的牌依次放入一列牌的末端。若放入之前这列牌中已有与这张牌点数相
同的牌,则小杨同学会将这张牌和点数相同的牌之间的所有牌全部取出队列(包括这两张牌本身)。

小杨同学现在有一个长度为 \(n\) 的卡牌序列 \(A\),其中每张牌的点数为 \(A_i\)\(1\le i\le n\))。小杨同学有 \(q\) 次询问。第 \(i\) 次(\(1\le i\le q\))询问时,小杨同学会给出 \(l_i,r_i\) 小杨同学想知道如果用下标在 \([l_i,r_i]\) 的所有卡牌按照下标顺序玩“接竹竿”的游戏,最后队列中剩余的牌数。

【输入】

一行包含一个正整数 \(T\),表示测试数据组数。

对于每组测试数据,第一行包含一个正整数 \(n\),表示卡牌序列 \(A\) 的长度。

第二行包含 \(n\) 个正整数 \(A_1,A_2,\dots,A_n\),表示卡牌的点数 \(A\)

第三行包含一个正整数 \(q\),表示询问次数。

接下来 \(q\) 行,每行两个正整数 \(l_i,r_i\) 表示一组询问。

【输出】

对于每组数据,输出 \(q\) 行。第 \(i\) 行(\(1\le i\le q\))输出一个非负整数,表示第 \(i\) 次询问的答案。

【输入样例】

1
6
1 2 2 3 1 3
4
1 3
1 6
1 5
5 6

【输出样例】

1
1
0
2

【算法标签】

《洛谷 P10264 接竹竿》 #倍增# #GESP# #2024#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

// 定义int为unsigned类型,因为第11号测试点需要unsigned才能通过,否则会TLE
#define int unsigned

// 变量声明
unsigned t, n, q;  // t: 测试用例数, n: 牌的数量, q: 查询次数

signed main()  // 由于使用了#define int unsigned,所以main函数需要改为signed
{
    // 读取测试用例数
    scanf("%d", &t);
    
    // 处理每个测试用例
    while (t--)
    {
        int a[15] = {};       // a[x]: 记录数字x最后一次出现的位置
        int nxt[100005] = {};  // nxt[i]: 记录与位置i的数字相同的下一个位置,0表示没有下一个
        
        // 读取牌的数量
        scanf("%d", &n);
        
        // 读取牌的序列
        for (int i = 1; i <= n; i++)
        {
            int x;
            scanf("%d", &x);
            
            // 建立链表:当前位置i连接到上一次出现相同数字的位置
            nxt[a[x]] = i;  // 将上一次出现位置a[x]的nxt指向当前位置i
            
            // 更新a[x]为当前位置i
            a[x] = i;
        }
        
        // 读取查询次数
        scanf("%d", &q);
        
        // 处理每个查询
        while (q--)
        {
            int ans = 0;  // 答案:最终留下的牌的数量
            int st, ed;    // 查询区间[st, ed]
            scanf("%d%d", &st, &ed);
            
            // 遍历区间内的每个位置
            for (int i = st; i <= ed; i++)
            {
                // 如果当前位置i没有相同数字在区间内(nxt[i]=0或在区间外)
                if (nxt[i] < st || nxt[i] > ed)
                {
                    ans++;  // 这张牌会留下来
                }
                else
                {
                    // 有相同数字在区间内,跳到相同数字的下一个位置
                    i = nxt[i];
                }
            }
            
            // 输出当前查询的答案
            printf("%d\n", ans);
        }
    }
    
    return 0;
}

【运行结果】

1
6
1 2 2 3 1 3
4
1 3
1
1 6
1
1 5
0
5 6
2
posted @ 2026-01-19 17:07  热爱编程的通信人  阅读(0)  评论(0)    收藏  举报