2024年第七届广西大学生程序设计大赛(正式赛)题解

在这里插入图片描述

榜单:CCPC榜单
|
知乎:如何评价第七届广西大学生程序设计大赛?
|
补题链接:codeforcesPTA

难度签到题普通题中等题难题
题号B E LF JA D H K MC G I
情况--

全部资料:一至七届 GXCPC广西大学生程序设计竞赛 题目与题解


签到题

B. Black Friday

黑色星期五

题目大意:

n 件物品,每件物品有一个原价和促销价。求折扣符合给定要求的物品的促销价之和。
1 ≤ n ≤ 10 ^ 4
给定的折扣计算方法:
p i − q i p i \frac{{pi-qi}}{{pi}} pipiqi

官方解题思路:

在这里插入图片描述

个人解题思路:

和官方一致。
满足折扣的条件如下:
a b ≤ p i − q i p i \frac{a}{b} \leq \frac{p_i - q_i}{p_i} bapipiqi
两侧同乘分母,或者说,十字交叉相乘(不涉及负数,不用考虑变号的)就是:
a ⋅ p i ≤ ( p i − q i ) ⋅ b a \cdot p_i \leq (p_i - q_i) \cdot b api(piqi)b

给定的int数据范围不大,相乘不会超int范围

参考代码c++(官方思路)

#include<iostream>
using namespace std;
int main()
{
    int n, a, b, p, q, sum = 0;
    cin >> n >> a >> b;
    while (n--) {
        cin >> p >> q;
        if (a * p <= (p - q) * b) {
            sum += q;
        }
    }
    cout << sum;
    return 0;
}

E. Epsilon Estuary

ε河口

题目大意:

有 n 只史莱姆,第 i 只血量是 xi 。
每次史莱姆受到攻击会裂成两个,受到攻击后的血量是 x 的话,会裂成 ⌊x/2⌋ 和 ⌈x/2⌉。
现在你可以使用法术,每次对全场所有史莱姆造成 y 点攻击。
问清场最少需要使用多少次法术。
1 ≤ n ≤ 10 ^ 5, 1 ≤ xi, y ≤ 10 ^ 18

官方解题思路:

在这里插入图片描述

个人解题思路:

官方题解说得对!找出最大值,再进行处理。
数据规模大,注意读写速度。

参考代码c++(官方思路)

#include<iostream>
using namespace std;
int main() {
    int t;
    cin >> t;
    while (t--) {
        long long n, y, maxn = 0, cnt = 0;
        scanf("%lld %lld", &n, &y);
        while (n--) {
            long long x;
            scanf("%lld", &x);
            maxn = max(maxn, x);
        }
        while (maxn > 0) {
            maxn = (maxn - y + 1) / 2;
            cnt++;
        }
        printf("%lld\n", cnt);
    }
    return 0;
}

L. Loong

龙年

题目大意:

输出第 x 年之后的下一个龙年是哪年。

1 ≤ x ≤ 9999

官方解题思路:

在这里插入图片描述

个人解题思路:

众所周知,2024 年是龙年,则 2024 ± 12 * n 年都是龙年。

x 的范围不大(1 ≤ x ≤ 9999),可以这么解:换言之, 8 + 12 * n 年都是龙年。

  • x < 8:直接输出 8
  • x ≥ 8:输出的数 ≤ x + 12,且满足 8 + 12 * n
    假设 结果为 res ,可设 res = x + i,可知 i ≤ 12
    那么 res = 8 + 12 * n
    也就 x + i = 8 + 12 * n
    移项 i = 8 + 12 * n - x
    等同 i = 12 - (x - 8) % 12
    结果 res = x + 12 - (x - 8) % 12

r e s = { 8 , 1 ≤ x ≤ 8 x + 12 − ( x − 8 ) % 12 , 8 ≤ x ≤ 9999 {res = \begin{cases} 8, & 1 \leq x \leq 8 \\ x + 12 - (x - 8) \% 12, & 8 \leq x \leq 9999 \\ \end{cases}} res={8,x+12(x8)%12,1x88x9999


当然也可以不分开讨论,那样就是:
i = 12 + (x + 12 - 8) % 12 ⇨ i = 12 + (x + 4) % 12
res = x + 12 + (x + 4) % 12

r e s = x + 12 − ( x + 4 ) % 12 , 1 ≤ x ≤ 9999 res = x + 12 - (x + 4) \% 12, 1 \leq x \leq 9999 res=x+12(x+4)%12,1x9999

那自然有很多种写法。

参考代码c++(官方思路)

#include<iostream>
using namespace std;
int main()
{
    int x;
    cin >> x;
    cout << ((x + 4) / 12) * 12 + 8;
    return 0;
}

参考代码c++(个人思路 - 分开讨论)

#include <iostream>
using namespace std;
int main()
{
    int x, res;
    cin >> x;
    
    // if-else 写法
    if (x < 8) {
        res = 8;
    } else {
		res = x + 12 - (x - 8) % 12;
    }
    
    // 三元表达式 写法
    // res = x < 8 ? 8 : x + 12 - (x - 8) % 12;
    
    cout << res;
    return 0;
}

参考代码c++(个人思路 - 不分开讨论)

#include<iostream>
using namespace std;
int main()
{
    int x;
    cin >> x;
    cout << x + 12 - (x + 4) % 12;
    return 0;
}

普通题

F. Farewell GXCPC!

再见,GXCPC!

题目大意:

有n 个题,每个题有一个难度di 和一个有趣程度fi 。
Colin 要从中选一些组成一场比赛,满足:

  1. 所有选中题目难度之和∈ [L, R]
  2. 所有选中题目有趣程度最大。
    现在Colin 会进行q 组询问,每次给出一对L, R ,求此时可能的选中题目有趣程度
    之和的最大值。
    1 ≤ n, di, Li, Ri ≤ 5000, 1 ≤ fi, q ≤ 105

官方解题思路:

在这里插入图片描述

GPT-4o解题思路:

官方题解说得对。

以下内容由 GPT-4o 生成,仅供参考

  1. 动态规划解决背包问题:
  • 我们使用一个动态规划(DP)数组 dp,其中 dp[j] 表示难度和恰好为 j 的最大有趣程度。
  • 初始化 dp[0] = 0(因为难度为0时有趣程度为0),其他 dp[j] 初始化为 -1(表示无法达到的状态)。
  1. 填充DP表:
  • 遍历每个题目,并更新DP表。为了防止覆盖当前迭代的结果,我们从后向前更新DP表。
  • 对于每个题目的难度 d 和有趣程度 f,更新 dp[j] 为 max(dp[j], dp[j - d] + f),其中 j 从 5000 到 d。
  1. 区间最大值查询(RMQ):
  • 填充完DP表后,我们需要对其进行预处理,以便能够高效地回答区间最大值查询。我们可以使用稀疏表(Sparse Table)或者线段树。为了简便,我们使用稀疏表。
  1. 回答查询:
  • 对于每个查询给定的区间 [Li, Ri],使用预处理好的RMQ结构获取该区间内的最大 dp[j] 值。

参考代码c++(GPT-4o生成)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 5000;
const int INF = 1e9;

int dp[MAXN + 1];
int sparse[MAXN + 1][13];

void preprocessSparseTable(int n) {
    for (int i = 0; i <= n; ++i) {
        sparse[i][0] = dp[i];
    }
    for (int j = 1; (1 << j) <= n + 1; ++j) {
        for (int i = 0; (i + (1 << j) - 1) <= n; ++i) {
            sparse[i][j] = max(sparse[i][j - 1], sparse[i + (1 << (j - 1))][j - 1]);
        }
    }
}

int querySparseTable(int L, int R) {
    int j = 31 - __builtin_clz(R - L + 1);
    return max(sparse[L][j], sparse[R - (1 << j) + 1][j]);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, q;
    cin >> n >> q;
    
    vector<pair<int, int>> problems(n);
    for (int i = 0; i < n; ++i) {
        cin >> problems[i].first >> problems[i].second;
    }
    
    fill(dp, dp + MAXN + 1, -INF);
    dp[0] = 0;
    
    for (auto [d, f] : problems) {
        for (int j = MAXN; j >= d; --j) {
            if (dp[j - d] != -INF) {
                dp[j] = max(dp[j], dp[j - d] + f);
            }
        }
    }
    
    preprocessSparseTable(MAXN);

    while (q--) {
        int L, R;
        cin >> L >> R;
        int result = querySparseTable(L, R);
        if (result == -INF) {
            cout << -1 << '\n';
        } else {
            cout << result << '\n';
        }
    }

    return 0;
}

J. Judge System with Random

系统随机判题

题目大意:

某场比赛一个题,评测系统会随机返回正确/错误。

一个人如果至少有一个提交的返回结果是正确的,罚时计算方式是,第一次正确的提交时间+ (此前提交次数)× 20 。

一个人如果至少有一个提交的返回结果是正确的,并且罚时是所有的这些人里最小的,那么他就是冠军。如果有多个最小的这些人会共享冠军。

Colin 和Eva 分别进行了n 次提交和m 次提交,并给出相应的提交时间。

问所有的2n+m 种可能性中,有多少种Colin 会成为冠军。
1 ≤ n, m ≤ 105

官方解题思路:

在这里插入图片描述

群友解题思路:

下面的代码思路源自群友的代码,和官方思路一致。

  • 定义了一个用于快速计算大数幂模的函数,采用了二分法(递归乘法)来实现。
  • 使用双指针方法遍历 Colin 的提交时间,并计算相应的惩罚时间。
  • 对于每一个 Colin 的提交,检查有多少 Eva 的惩罚时间小于当前 Colin 的惩罚时间。
  • 累积计算所有可能的组合数,最终计算出符合条件的组合数。

参考代码c++(群友思路)

感谢 南宁训练联盟学生群 的 群友提供的代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const int mod=998244353;
int p[N];
int q[N];

// 快速幂函数,用于计算 (a^b) % p
long long kuai(long long a,long long b,long long p){
	long long sum=1;
	while(b){
		if(b&1)sum=sum*a%p;
		b=b>>1;
		a=a*a%p;
	}
	return sum;
}

int main(){
	int n,m;
	cin>>n>>m;
	
	for(int i=1;i<=n;i++){
		cin>>p[i];	
	}

	for(int i=1;i<=m;i++){
		cin>>q[i];
	}

	ll sum=0;
	ll en=0;

	q[m+1]=1e17; // 设置一个极大值,作为哨兵
	ll cnt=0;
	ll cnt2=0;

	for(int i=1;i<=n;i++){
		sum=p[i]+20*(i-1); // 计算 Colin 的惩罚时间
		
		// 统计 Eva 的所有惩罚时间小于当前 Colin 惩罚时间的情况数
		while(q[cnt2+1]+20*(cnt2)<sum){
			cnt2++;
            cnt+=kuai(2,(m-cnt2),mod);
            cnt%=mod;
		}
	
		en+=(kuai(2,n-i,mod)*cnt)%mod;
		en%=mod;
	}

	en+=kuai(2,m,mod);
	en%=mod;
    en=((kuai(2,n+m,mod))-en+mod)%mod;
	en%=mod;
	cout<<en;
}

中等题

其他题还没写到,先鸽着🧐


难题

超出我所能想象的程度了hhhh,希望有大佬可以补上😊


难度题号备注
签到题B E L
普通题F J
中等题A D H K M-
难题C G I-
  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值