1

GESP认证C++编程真题解析 | 202309 六级

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

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

适合人群:

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

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


编程题

B3873 小杨买饮料

【题目来源】

洛谷:[B3873 GESP202309 六级] 小杨买饮料 - 洛谷

【题目描述】

小杨来到了一家商店,打算购买一些饮料。这家商店总共出售 \(N\) 种饮料,编号从 \(0\)\(N-1\),其中编号为 \(i\) 的饮料售价 \(c_i\) 元,容量 \(l_i\) 毫升。

小杨的需求有如下几点:

  1. 小杨想要尽可能尝试不同种类的饮料,因此他希望每种饮料至多购买 \(1\) 瓶;
  2. 小杨很渴,所以他想要购买总容量不低于 \(L\) 的饮料;
  3. 小杨勤俭节约,所以在 \(1\)\(2\) 的前提下,他希望使用尽可能少的费用。

方便起见,你只需要输出最少花费的费用即可。特别地,如果不能满足小杨的要求,则输出 no solution

【输入】

第一行两个整数 \(N,L\)

接下来 \(N\)行,依次描述第 \(i=0,1,\cdots,N-1\) 种饮料:每行两个整数 \(c_i,l_i\)

【输出】

输出一行一个整数,表示最少需要花费多少钱,才能满足小杨的要求。特别地,如果不能满足要求,则输出 no solution

【输入样例】

5 100 
100 2000
2 50
4 40
5 30
3 20

【输出样例】

9

【算法标签】

《洛谷 B3873 小杨买饮料》 #动态规划DP# #背包DP# #GESP# #2023#

【代码详解】

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

const int N = 505;            // 最大物品数量
const int INF = 0x3f3f3f3f;   // 定义无穷大
int n, L;                     // n: 物品数量, L: 最小需要的长度
int c[N], l[N];               // c[i]: 第i个物品的价格, l[i]: 第i个物品的长度
int dp[1000005];              // dp[j]: 总长度至少为j时的最小花费

int main()
{
    // 输入物品数量和需要的最小长度
    cin >> n >> L;
    
    // 输入每个物品的价格和长度
    for (int i = 1; i <= n; i++)
    {
        cin >> c[i] >> l[i];
    }
    
    // 初始化dp数组为无穷大
    memset(dp, 0x3f, sizeof(dp));
    dp[0] = 0;  // 总长度为0时的最小花费为0
    
    // 动态规划:0-1背包的变形(至少型背包)
    for (int i = 1; i <= n; i++)  // 遍历每个物品
    {
        for (int j = 1000000; j >= l[i]; j--)  // 从大到小遍历,保证每个物品只用一次
        {
            // 状态转移方程:
            // 不选当前物品:dp[j] 保持不变
            // 选当前物品:dp[j-l[i]] + c[i]
            // 取两者最小值
            dp[j] = min(dp[j], dp[j - l[i]] + c[i]);
        }
    }
    
    // 在满足长度至少为L的所有方案中寻找最小花费
    int ans = INF;
    for (int i = L; i <= 1000000; i++)
    {
        ans = min(ans, dp[i]);
    }
    
    // 输出结果
    if (ans == INF)
    {
        // 没有找到满足条件的方案
        cout << "no solution" << endl;
    }
    else
    {
        // 输出最小花费
        cout << ans << endl;
    }
    
    return 0;
}

【运行结果】

5 100
100 2000
2 50
4 40
5 30
3 20
9

小杨的握手问题

【题目来源】

洛谷:[B3874 GESP202309 六级] 小杨的握手问题 - 洛谷

【题目描述】

小杨的班级里共有 \(N\) 名同学,学号从 \(0\)\(N-1\)

某节课上,老师安排全班同学进行一次握手游戏,具体规则如下:老师安排了一个顺序,让全班 \(N\) 名同学依次进入教室。每位同学进入教室时,需要和 已经在教室内学号小于自己 的同学握手。

现在,小杨想知道,整个班级总共会进行多少次握手。

提示:可以考虑使用归并排序进行降序排序,并在此过程中求解。

【输入】

输入包含 \(2\) 行。第一行一个整数 \(N\) ,表示同学的个数;第二行 \(N\) 个用单个空格隔开的整数,依次描述同学们进入教室的顺序,每个整数在 \(0 \sim N-1\) 之间,表示该同学的学号。

保证每位同学会且只会进入教室一次。

【输出】

输出一行一个整数,表示全班握手的总次数。

【输入样例】

4 
2 1 3 0

【输出样例】

2

【算法标签】

《洛谷 B3874 小杨的握手问题》 #树状数组# #递归# #排序# #GESP# #2023#

【代码详解】

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

#define int long long
const int N = 300005;  // 树状数组大小,要大于最大可能的值
int n;                 // 数组长度
int ans;               // 逆序对总数
int tr[N];             // 树状数组

/**
 * 计算lowbit:返回x的二进制表示中最低位的1所对应的值
 * 例如:lowbit(6)=2,因为6的二进制是110,最低位的1表示2
 * @param x 输入数字
 * @return lowbit值
 */
int lowbit(int x)
{
    return x & -x;  // 利用补码性质:x & -x
}

/**
 * 树状数组更新操作
 * 在位置x上增加c
 * @param x 更新位置
 * @param c 增加的值
 */
void add(int x, int c)
{
    // 从x开始,沿lowbit路径向上更新所有包含x的区间
    for (int i = x; i <= N; i += lowbit(i))
    {
        tr[i] += c;
    }
}

/**
 * 树状数组查询操作
 * 查询前缀和[1, x]
 * @param x 查询位置
 * @return 前缀和
 */
int query(int x)
{
    int res = 0;
    // 从x开始,沿lowbit路径向下累加
    for (int i = x; i; i -= lowbit(i))
    {
        res += tr[i];
    }
    return res;
}

signed main()  // 因为使用了#define int long long
{
    // 输入数组长度
    cin >> n;
    
    // 从后向前遍历数组
    for (int i = n; i >= 1; i--)
    {
        int x;
        cin >> x;
        x++;  // 将数值从0-based转为1-based,避免树状数组处理0
        
        // 查询在当前位置之前(在原始顺序中)有多少个比x小的数
        // 因为是从后向前遍历,所以query(x)返回的是已经处理过的数中小于等于x的数量
        // 但我们需要的是严格小于x的数量,所以这里有问题
        ans += query(x);
        
        // 将当前数加入树状数组
        add(x, 1);
    }
    
    // 输出逆序对总数
    cout << ans << endl;
    
    return 0;
}

【运行结果】

4 
2 1 3 0
2
posted @ 2026-01-18 21:46  热爱编程的通信人  阅读(0)  评论(0)    收藏  举报