P11247 [GESP202409 六级] 算法学习

gesp(C++六级)(12)洛谷:P11247:[GESP202409 六级] 算法学习 阅读详情

记录122

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;// 定义常量 MAXN,根据题目 n, m <= 10^5
vector<int> ques[MAXN];// 静态数组配合动态数组:ques[i] 存储第 i 种算法的所有题目加分值
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int m,n,k;// m为算法种类数,n为题目总数,k为目标掌握程度
	cin>>m>>n>>k;
	vector<int> a(n+1);// 数组 a 用于存储每道题对应的知识点编号(从下标 1 开始使用)
	vector<int> b(n+1);// 数组 b 用于存储每道题对应的加分值(从下标 1 开始使用)
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=1;i<=n;i++) ques[a[i]].push_back(b[i]);
	// 核心分组步骤:将第 i 道题的加分 b[i],存入它所属的知识点 a[i] 对应的向量中
	long long total_ques=0; // 记录完成目标总共需要的最少题目数量(用 long long 防止累加溢出)
	int max_cnt=0; // 记录所有算法中,需求量最大的那个算法所需的题目数
	int mx_need_i=-1;// 【新增】用来记录需求量最大的那个知识点的编号
	for(int i=1;i<=m;i++){// 遍历 m 种算法,进行贪心处理
		sort(ques[i].begin(),ques[i].end(),greater<int>());
		// 将该算法对应的所有题目按加分从大到小排序,保证优先做加分高的题
		int cur_sum=0;// 当前算法的累计掌握程度
		int need_cnt=0;// 当前算法达到目标 k 所需要的题目数量
		for(int score:ques[i]){// 依次遍历排好序的题目加分
			cur_sum+=score;// 累加掌握程度
			need_cnt++; // 做题数量加一
			if(cur_sum>=k) break;// 一旦达到目标 k,立刻停止选择该算法的后续题目
		}
		if(cur_sum<k){// 如果该算法所有题目加起来都达不到目标 k,说明无解
			cout<<-1<<"\n";
			return 0;
		}
		total_ques+=need_cnt;// 将该算法所需的最少题目数加入总题数
		if(need_cnt>max_cnt){max_cnt=need_cnt;mx_need_i=i;}// 【修改】更新最大值的同时记录下标
	} 
	long long other_cnt=total_ques-max_cnt; // 计算除了需求最多的算法外,其余算法所需的总题数
	if(max_cnt<=other_cnt+1){// 【修改】如果普通插空能成功,直接输出并结束
		cout<<total_ques<<"\n";
		return 0;
	}
	// --- 【新增的补救逻辑】---
	// 走到这里说明普通插空失败,尝试去“借”其他知识点没用过的废题来当隔板
	long long last=0;// 记录其他知识点剩下的、没被选中的题目总数(工具人库存)
	for(int i=1;i<=m;i++){
		if(i!=mx_need_i){// 只统计除了最大需求者之外的其他知识点
			int used=0,sum=0;// 重新算一下第 i 个知识点实际用了多少道题
			for(int score:ques[i]){sum+=score;used++;if(sum>=k)break;}
			last+=ques[i].size()-used;// 总题数减去必须做的题数 = 可以借的废题数
		}
	}
	// 最终带工具人的插空判定:左边是必选题需要的空隙,右边是原本的其他题加上借来的废题
	if(max_cnt-1<=other_cnt+last)cout<<2LL*max_cnt-1<<"\n";// 能隔开!最优策略是排成 必选-工具人-必选... 的形式
	else cout<<-1<<"\n";// 就算借了所有废题也填不满空隙,彻底无解
	return 0;//结束程序 
}

题目传送门https://www.luogu.com.cn/problem/P11247


前言

我是一名专注信奥赛(CSP-J/S、NOIP)的教练。

  • 如果你觉得这篇题解对你有帮助,欢迎点击关注我的优快云账号,我会持续更新高质量算法解析。
  • 我深知算法思维的构建远比单纯通过题目更重要,本系列题解不局限于AC代码的堆砌,而是致力于拆解题目背后的逻辑链条与核心知识点
  • 备赛路上若遇瓶颈,欢迎随时评论或私信,我将甄选典型疑难问题,通过视频讲解或撰写专项文章的形式,为你提供深度答疑。

💡 核心解题思路推导

这道题可以拆解为三个步骤来解决:

第一步:贪心选取(最少做题数)

对于每一种算法知识点 ii ,我们的目标是用最少的题目数量让掌握度达到 kk 。

  • 策略:将属于该知识点的所有题目按加分 bibi​ 从大到小排序。
  • 操作:依次选取加分最高的题目,直到累计分数 ≥k≥k 。
  • 记录:记录下每种知识点所需的最少题目数 need_cnt,以及所有知识点的总题目数 total_ques。
第二步:可行性初判(无解情况)

在贪心选取的过程中,如果发现某一种算法知识点,即使把所有相关题目都做了,分数 still <k<k ,那么直接输出 -1,因为目标无法达成。

第三步:插空排列(避免连续)

这是本题最难的逻辑点。假设我们已经算出了每种知识点需要做的题目数(cnt[1], cnt[2], ..., cnt[m])。

  • 找出最大值:设需求最大的知识点需要做 max_cnt 道题。
  • 其余总和:设其他所有知识点需要做的题目总数为 other_cnt。
  • 插空原理:要把 max_cnt 个相同的题目隔开(不能相邻),至少需要 max_cnt - 1 个其他知识点的题目来充当“隔板”。
    1. 情况 A(容易):如果 other_cnt >= max_cnt - 1。
      • 说明我们手头的“其他必做题”足够多,可以直接插空。
      • 答案就是总题数 total_ques。
    2. 情况 B(困难):如果 other_cnt < max_cnt - 1。
      • 说明“必做题”不够当隔板。这时我们需要去“借”那些不需要做的题目(即废题)来当工具人。
      • 计算废题数 last:遍历除最大需求知识点外的所有组,计算每组没被选中的题目数量(总题数 - 必做题数)。
      • 借题插空:如果 other_cnt + last >= max_cnt - 1,说明借了废题后能隔开。此时的最优排列策略是:[必选] [工具人/废题] [必选] ...。这种排列的最短长度是 2×max_cnt−12×max_cnt−1 。
      • 彻底无解:如果连废题都借光了还不够隔板,输出 -1。

🧩 代码解释

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10; // 定义数组大小常量,题目数据范围是 10^5
vector<int> ques[MAXN]; // 邻接表思想:ques[i] 存储所有属于知识点 i 的题目加分值
  • 解释:这里使用了静态数组 ques 配合 vector,这是处理“分组数据”的常用高效写法。
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); // 优化输入输出流,加快读取速度(题目数据量较大)
    
    int m,n,k;
    cin>>m>>n>>k;
    vector<int> a(n+1); // a[i] 表示第 i 道题的知识点编号
    vector<int> b(n+1); // b[i] 表示第 i 道题的加分值
    
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    
    // 核心分组逻辑
    for(int i=1;i<=n;i++) 
        ques[a[i]].push_back(b[i]);
  • 解释:将输入的题目按知识点分类。例如所有知识点为 1 的题,其加分值都被放入 ques[1] 这个 vector 中。
    long long total_ques=0; // 总共需要做的题目数量(用 long long 防止累加溢出)
    int max_cnt=0;          // 记录单个知识点所需的最大题目数
    int mx_need_i=-1;       // 记录需求最大的那个知识点的编号(为了后面排除它计算废题)
  • 解释:total_ques 定义为 long long 是为了保险,虽然题目 n≤10^5 ,但养成好习惯。
    // 遍历每一种算法知识点
    for(int i=1;i<=m;i++){
        // 1. 贪心排序:将该知识点下的题目按加分从大到小排序
        sort(ques[i].begin(),ques[i].end(),greater<int>());
        
        int cur_sum=0;     // 当前知识点累计分数
        int need_cnt=0;    // 当前知识点需要做的题目数
        
        // 2. 贪心选取:从高分题开始做,直到达到目标 k
        for(int score: ques[i]){
            cur_sum += score;
            need_cnt++;
            if(cur_sum >= k) break;
        }
        
        // 3. 判定无解:如果该知识点分数不够 k
        if(cur_sum < k){
            cout << -1 << "\n";
            return 0; // 直接结束程序
        }
        
        // 4. 更新全局变量
        total_ques += need_cnt;
        if(need_cnt > max_cnt){ 
            max_cnt = need_cnt; 
            mx_need_i = i; // 记录下是哪个知识点需求最大
        }
    } 
  • 解释:这是第一阶段的逻辑,确定了“最少要做哪些题”。
    long long other_cnt = total_ques - max_cnt; // 其他知识点需要做的题目总数
    
    // 情况 A:如果其他题足够作为隔板 (other_cnt >= max_cnt - 1)
    if(max_cnt <= other_cnt + 1){
        cout << total_ques << "\n";
        return 0;
    }
  • 解释:max_cnt <= other_cnt + 1 等价于 max_cnt - 1 <= other_cnt。这是插空法的基本公式。
    // 情况 B:其他“必做题”不够当隔板,需要借“废题”
    long long last = 0; // 统计可以借来的“废题”数量
    
    for(int i=1;i<=m;i++){
        if(i != mx_need_i){ // 只统计非最大需求的知识点(不能借自己的废题)
            int used = 0, sum = 0;
            // 重新计算该知识点实际用了多少道“必做题”
            for(int score: ques[i]){ 
                sum += score; 
                used++; 
                if(sum >= k) break;
            }
            // 累加该知识点的“废题”数量(总题数 - 必做题数)
            last += ques[i].size() - used; 
        }
    }
    
    // 最终判定:借了废题后,隔板是否够用?
    // max_cnt - 1 是需要的隔板数
    // other_cnt + last 是现有的隔板总数(必做题 + 废题)
    if(max_cnt - 1 <= other_cnt + last)
        cout << 2LL * max_cnt - 1 << "\n"; // 能隔开!最短长度是 2*max_cnt - 1
    else 
        cout << -1 << "\n"; // 彻底无解
  • 解释:2LL * max_cnt - 1 中的 LL 表示 Long Long,防止乘法溢出。这个公式的含义是:max_cnt 个必选题,中间插入 max_cnt - 1 个工具人(废题),总长度即为 n+(n−1)=2n−1n+(n−1)=2n−1 。

算法思维提炼

维度经验总结避坑指南
题眼识别看到“最少做题数” →→ 贪心;看到“不能连续相同” →→ 插空法不要盲目套用模板,需根据题意组合使用
极值思维排列约束问题中,需求量最大的元素决定了整体结构必须记录最大值及其下标,它是后续所有判定的基准
隐藏资源题目中“未被选中的冗余数据”往往是破局的关键工具当常规条件不满足时,检查是否有“废料”可以二次利用
数据类型涉及大量累加和乘法运算时,需防范整数溢出使用 long long 并在乘法时加上 LL 后缀
题解:洛谷 P11395 喵喵喵幼儿园 等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。对于每个问题,输出一行一个字符串,表示你对于这个问题的答案。喵喵喵群里面,吃喵喵是坏文明。为仅含小写字母的非空字符串。对于每个问题,你可以回答。输入的第一行有一个正整数。个问题,每个问题形如。#入门# #字符串入门#本文分享的必刷题目是从。行,每行有一个问题。 阅读详情

相关推荐

题解:洛谷 P11247 [GESP202409 六级] 算法学习

小杨认为连续学习两道相同知识点的题目是不好的,小杨想请你编写程序帮他计算出他最少需要学习多少道题目才能使得他在完成学习目标的同时避免连续学习两道相同知识点的题目。输出一个整数,代表小杨最少需要学习题目的数量,如果不存在满足条件的方案,输出。,且不能连续学习两道相同知识点的题目。求最少学习题目数,或判断无解。道题目来帮助自己学习,每道题目至多学习一次。,代表算法种类数,题目数和目标掌握程度。,代表每道题目提升的掌握程度。道题目,每道题目属于知识点。种算法的掌握程度均至少为。,代表每道题目的知识点。

团爸讲算法 278

洛谷 P11247 [GESP202409 六级] 算法学习-普及/提高-

小杨认为连续学习两道相同知识点的题目是不好的,小杨想请你编写程序帮他计算出他最少需要学习多少道题目才能使得他在完成学习目标的同时避免连续学习两道相同知识点的题目。输出一个整数,代表小杨最少需要学习题目的数量,如果不存在满足条件的方案,输出 -1。一种最优学习顺序为第一道题,第三道题,第四道题,第二道题。道题目来帮助自己学习,每道题目最多学习一次。,代表算法种类数,题目数和目标掌握程度。,代表每道题目提升的掌握程度。种算法的初始掌握程度均为。种算法的掌握程度均至少为。,代表每道题目的知识点。

weixin_37253733的博客 1302

gesp(C++六级)(11)洛谷:P11246:[GESP202409 六级] 小杨和整数拆分

gesp(C++六级)(11)洛谷:P11246:[GESP202409 六级] 小杨和整数拆分

王老师青少年编程 1452

CCF-GESP计算机学会等级考试2024年9月六级C++T2算法学习

解析:用贪心算法找到每个知识点达到目标所需要的最小题量,若其中最大值超过其他总和+1,则无法避免连续同一个知识点。

长春高老师编程 1460

GESP六级真题考点分析和解题思路

本文分析了GESP六级考试的18道真题,涵盖动态规划、树形结构、图论算法等核心考点。重点题目包括下楼梯(动态规划)、工作沟通(LCA算法)、运送物资(网络流)等。试题难度以普及级为主,涉及拓扑排序、树形DP、二分答案等典型算法。备考建议掌握动态规划状态转移、树结构的DFS遍历、图论算法实现等关键技能,并熟悉提供的代码模板(如拓扑排序和树直径计算)。通过系统练习这些高频题型和算法模板,可以有效提升六级考试通过率。

lan_in的博客 776

GESP C++ 六级 题目详解

包含CSP-J、CSP-S、CSP-X、NOIP、NOI、GESP、USACO、CCC,真题及模拟题,欢迎订阅💕~

YYX_YYJ的博客 748

《P11247 [GESP202409 六级] 算法学习》

题目摘要:小杨需要学习m种算法,每种初始掌握程度为0。现有n道题目,每道题对应一个知识点,学习后能提升该知识点的掌握程度。目标是对所有m种算法的掌握程度至少达到k,且不能连续学习相同知识点的题目。要求计算最少需要学习多少道题才能达标,若无解则输出-1。 输入包含m,n,k,以及每道题的知识点和提升值。输出最少学习题数或-1。 样例1展示了通过特定顺序学习4道题可达标,而样例2则无解。数据规模可达1e5。

Jasmine_llq的博客 482

CAN基础知识

CAN基础知识

shouchen1的博客 9152

打卡信奥刷题(2047)用C++实现信奥 P11247 [GESP202409 六级] 算法学习 题解

题目要求小杨通过选择题目学习算法,使得每种算法的掌握程度至少达到k,同时避免连续学习相同知识点的题目。输入包括算法种类数m、题目数n和目标k,以及每道题的知识点和提升值。输出最少需要学习的题目数,若无法满足条件则输出-1。样例1显示最优解为4道题,而样例2则无解输出-1。C++实现通过排序和统计各知识点经验值及题目数来解决该问题,判断条件为是否所有算法达标且满足题目选择约束。时间复杂度需处理高达1e5的数据规模。

Loge谈信奥--一个专注于信奥人的博客 1204

fastadmin云快充充电桩系统部署文档uniapp

多商户 嘎嘎快充V1.0部署文档 一、服务器环境: 服务器配置4核心8GB内存5M带宽以上配置 VX next1402 只支持linux环境 nginx1.22 php7.2 开启redis、fileinfo扩展,关闭禁用workerman gatewayworkerman需要的函数,如pcntl相关的函数 mysql5.7 supervisor redis 注意: 1.站点必须配置https、websocket配置wss 2.注意开放直连服务端口:2024,并添加到安全组 二、必

itholiday2014的博客 1632

海康威视Web3.0插件实战:快速部署摄像头实时预览方案

本文详细介绍了海康威视Web3.0插件的实战应用,包括快速部署摄像头实时预览方案的完整流程。从插件下载安装到摄像头连接配置,再到浏览器兼容性解决方案,帮助开发者和IT人员高效实现网页端监控功能。特别针对预览功能调优和多摄像头管理等高级应用提供了实用技巧。

weixin_29266679的博客 348

GESP2024年9月认证C++六级( 第三部分编程题(2)算法学习)

GESP2024年9月认证C++六级( 第三部分编程题(2)算法学习)

汉克老师的博客 507

告别交越失真:手把手教你设计高性能互补输出级电路(LTspice实测)

本文深入剖析音频放大器中常见的交越失真问题,并提供基于LTspice仿真的实战解决方案。通过对比二极管偏置、Vbe倍增器和集成运放驱动三种经典方案,手把手指导设计高性能互补输出级电路,涵盖原理分析、仿真验证及实物调试要点,助力消除音频失真,提升音质。

weixin_29190573的博客 553

【GESP2409六级】小杨和整数拆分 算法学习

【GESP2409六级】小杨和整数拆分 算法学习

青少年趣味编程 1251

QT使用libssh2库通过密匙实现sftp协议上传文件

qt下使用libssh2通过密匙连接sftp服务器端

小米的修行之路 949

Agentic AI应用架构师如何提升AI应用的灵活性

可扩展性(Scalability):快速添加新功能或扩展任务范围(如Agent从“客服”扩展到“供应链管理”);可修改性(Modifiability):调整Agent的决策逻辑或动作策略,无需重构整个系统;鲁棒性(Robustness):在环境异常或数据噪声下保持性能稳定;自适应(Self-Adaptation):自主学习新场景,无需人工干预。状态空间(S):Agent能感知的所有内部/外部状态(如用户需求、环境数据);动作空间(A):Agent能执行的所有动作(如调用工具、发送消息);

项目管理的博客 604

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

阅读以下用动态规划解决的0-1背包问题的函数,假设背包的容量W是10kg,假设输入4个物的重量weight 分别为1,3,4,6(单位为kg),每个物品对应的价值values 分别为20,30,50,60,则函数的输出为( )。假设字母表 {a,b,c,d,e} 在字符串出现的频率分别为10%,15%,30%,16%,29%。因此,向下取整并加1后,最小深度为12。对上题中的二叉搜素树,当输入数组为[5,3,7,2,4,6,8]时,构建二叉搜索树,并采用如下代码实现的遍历方式,得到的输出是( )。

团爸讲算法 1065

TenserRt平台SMOKE 3D目标检测部署完整教程:从理论到实践

本教程详细介绍了在RK3588平台上部署SMOKE 3D目标检测模型的完整流程。SMOKE是一种创新的单阶段单目3D检测方法,通过关键点估计直接预测3D目标信息,有效解决了深度信息缺失等挑战。文章从理论基础出发,解析了SMOKE的核心算法和网络架构,包括DLA-34主干网络和关键点中心化策略。同时提供了详细的Docker环境配置、模型导出到ONNX格式的实践指南,以及TensorRT引擎构建和性能优化的关键技术要点。该教程为开发者在嵌入式平台上实现高效3D目标检测提供了完整的技术参考。

LXY_LOVE36的博客 373

[GESP202409 六级] 算法学习 [题解]

本题解给出了GESP202409六级算法题的C++解决方案。程序首先读取m个组、n个元素及其对应的值,按组排序后计算每组满足总和≥k所需的最小元素个数。若无法满足则输出-1。否则,检查各组元素数量的合理性:如果其他组元素总数足够,输出总元素数;否则检查补充元素后能否满足要求,能则输出2*max-1,否则输出-1。该解法通过排序和贪心策略有效解决问题。

yy13736的博客 285

FC7300 SPI MCAL配置引导

Example - QMI8A01z外设:Example - QMI8A01z外设:

舊梦的博客 260

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

记——那次难忘的GESP六级考试(202603)+编程题题解

本文记录了作者参加GESP六级考试的全过程,重点描述了备考和考试当天的经历。作者详细列出了自己完成的13道编程题目及解题思路,包括DP、贪心、树状数组等算法题,同时也提到未完成的8道题目。考试当天经历了忘带鼠标的意外,利用触控板继续练习。文章还提到选择题涉及动态规划、树遍历等基础知识,整体展现了作者从紧张备考到从容应考的心路历程,以及面对突发状况的应对能力。

2401_84010520的博客 641

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

洛谷 P1247 取火柴游戏 题解

题目大意:太简单了相信大家都看得懂,那就不讲了吧其实这题是Nim游戏这个博弈论模型的裸题,你只要知道Nim游戏是什么,这题根本不难做,比较难处理的就是输出先手必赢时第一步应该怎么走,因为Nim游戏的结论是当a1^a2^……^an=0时,后手必赢,那这种先手必赢的情况,一定只需要在某一堆取完之后使得a1^a2^……^an=0即可,那这怎么求呢,那我们可以像后手必赢局势时后手的走法一样就可以了(你问我...

a_forever_dream的博客 493

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

GESP真题解析 (选取一部分9月) & 如何速通GESP?两篇文章教会你!(下)(通过题目来讲)

GESP真题2024年9月解析(上)

2301_79267246的博客 1552

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 396
上一篇: P10722 [GESP202406 六级] 二叉树
下一篇: P11375 [GESP202412 六级] 树上游走
谢天谢地AC了 | 信奥教练
博客等级 码龄1年 53粉丝 177原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值