csp信奥赛C++高频考点专项训练之贪心算法 --【删数问题】:删数问题2

csp信奥赛C++高频考点专项训练之贪心算法 --【删数问题】:删数问题2

题目描述

一个集合有如下元素: 1 1 1 是集合元素;若 P P P 是集合的元素,则 2 × P + 1 2\times P+1 2×P+1, 4 × P + 5 4\times P+5 4×P+5 也是集合的元素。

取出此集合中最小的 k k k 个元素,按从小到大的顺序组合成一个多位数,现要求从中删除 m m m 个数位上的数字,使得剩下的数字最大,编程输出删除前和删除后的多位数字。

注:不存在所有数被删除的情况。

输入格式

只有一行两个整数,分别代表 k k k 和 m m m。

输出格式

输出为两行两个整数,第一行为删除前的数字,第二行为删除后的数字。

输入输出样例 1
输入 1
复制代码
5 4
输出 1
复制代码
137915
95
数据规模与约定
  • 对于 30 % 30\% 30% 的数据,保证 1 ≤ k , m ≤ 300 1\le k,m\le300 1≤k,m≤300。
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ k , m ≤ 3 × 10 4 1\le k,m\le3\times10^4 1≤k,m≤3×104。

思路分析

  1. 生成最小的 k 个集合元素

    集合定义:1 在集合中;若 P 在集合中,则 2P+1 和 4P+5 也在集合中。

    要得到最小的 k 个元素,可以使用最小堆(优先队列)进行 BFS。

    • 初始将 1 入堆,并用哈希集合记录已生成的数,避免重复。
    • 每次弹出堆顶(当前最小值),将其加入结果数组,然后生成两个新数,若未出现过则入堆。
    • 重复 k 次即得到有序的前 k 个元素。
  2. 拼接成多位数

    将每个元素转换为字符串,按顺序拼接得到长字符串 s。

  3. 删除 m 个数字使剩下的数字最大

    经典贪心问题:使用单调栈。

    • 遍历 s 的每个字符 c,当栈非空且栈顶字符 < c 且还有删除次数时,弹出栈顶(删除该数字),删除次数减 1。
    • 将 c 压入栈。
    • 遍历结束后若还有删除次数,从栈末尾删除相应个数。
      最终栈内字符即为所求的最大数字串。
  4. 输出

    第一行输出删除前的多位数 s,第二行输出删除后的多位数。

代码实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int k, m;
    cin >> k >> m;
    
    // 最小堆生成最小的k个元素
    priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆
    unordered_set<long long> vis; // 去重
    vector<long long> a; // 存放取出的元素
    
    pq.push(1);
    vis.insert(1);
    while (a.size() < k) {
        long long x = pq.top(); pq.pop();
        a.push_back(x);
        long long y1 = 2 * x + 1;
        long long y2 = 4 * x + 5;
        if (!vis.count(y1)) {
            pq.push(y1);
            vis.insert(y1);
        }
        if (!vis.count(y2)) {
            pq.push(y2);
            vis.insert(y2);
        }
    }
    
    // 拼接成多位数
    string s;
    for (long long v : a) {
        s += to_string(v);
    }
    
    // 贪心删除m个数字使剩余最大
    string st; // 栈
    int d = m;
    for (char c : s) {
        while (d > 0 && !st.empty() && st.back() < c) {
            st.pop_back();
            d--;
        }
        st.push_back(c);
    }
    if (d > 0) st.erase(st.end() - d, st.end());
    
    // 输出
    cout << s << "\n" << st << "\n";
    
    return 0;
}

功能分析

  • 生成模块:使用最小堆和哈希集合,时间复杂度 O(k log k),空间复杂度 O(k),生成前 k 个最小元素并保持有序。
  • 拼接模块 :遍历元素数组,调用 to_string 并连接,总长度 S 约为 k 乘以平均位数(对于 k=3e4,S 约 2e5),时间 O(S)。
  • 删除模块:单遍扫描字符串,利用栈维护单调递减趋势,时间复杂度 O(S),空间复杂度 O(S)。
  • 输出模块:直接输出两个字符串。

正确性:贪心删除策略保证了每次删除使剩余数字尽可能大的局部最优,全局最优由单调栈性质保证。

各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}

【秘籍汇总】(完整csp信奥赛C++学习资料):

1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转

4、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转

5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
雪度娃娃12 小时前
转向现代C++——在创建对象时注意区分()和{}
开发语言·c++
吴可可12312 小时前
用Bulge保持多段线圆弧连续性
算法·c#
Tisfy12 小时前
VSCode Docker(Code Server)首次调试C++长时间下载debuginfo问题
c++·vscode·docker
读书札记202212 小时前
C++ switch..case语句中变量跨域问题探讨及解决方法
开发语言·c++
qq_2965532712 小时前
矩阵逆时针旋转90度:三种解法从入门到精通
数据结构·python·算法·面试·矩阵
声声codeGrandMaster12 小时前
seq2seq概念和数据集处理
人工智能·pytorch·python·算法·ai
努力努力再努力wz12 小时前
【Redis入门系列】Redis基础命令详解:从客户端连接到数据读写、key 管理与过期机制
c语言·开发语言·数据结构·数据库·c++·redis·缓存
谙弆悕博士12 小时前
【附C源码】C语言实现散列表
c语言·开发语言·数据结构·算法·散列表·数据结构与算法
Peter·Pan爱编程12 小时前
输入输出:iostream 为什么不是 printf 的替代品
c++·输入输出·c++基础·iostream
kkeeper~12 小时前
0基础C语言积跬步之深入理解指针(5上)
c语言·开发语言·算法