CCF 第一届算法竞赛 CACC 考题回忆

题目清单

  • 目录
  • 1. 报数游戏
  • 2. 宝藏勘探
  • 3. 心智能力
  • 4. 牌型分组
  • 5. 资源分配

目录

  1. 报数游戏
  2. 宝藏勘探
  3. 心智能力
  4. 牌型分组
  5. 资源分配

1. 报数游戏

一群同学围着一圈坐,编号 1 1 1 n n n ,给定 m m m ,从第一个同学开始报数开始报 m m m 个后,第 m m m 位同学离场,从圆圈中离开,剩余同学继续每隔 m m m 个报数离场一个人,问最后剩余的那个同学编号是多少。

完了,我记得这题之前还在哪个博客见过,还是什么 B 站视频看过,这题是有对应的数学公式解法的,但是我忘记了,只能试试暴力方法,不过一看数据范围最大 1000 ,好家伙,这不打卡题嚒,直接暴力 AC。vector 配合迭代器每次删除一个,然后在新的剩余人数中求模得到新下标,对于容器来说,有了下标等价于有了迭代器位置,有了迭代器就可以删除元素,不用自己处理。

2. 宝藏勘探

在一个从 0 0 0 n n n 的数轴上,每个位置有一个宝藏辐射值。两位勘探员正在勘探宝藏,勘探过的位置中的最大值和最小值之差代表整块数轴地的辐射值,能反映这块地方的宝藏可能性。两位勘探员分别从数轴的两侧相向而行,但是他们之间有矛盾,不愿意隔得太近,两位勘探员中间只剩 k k k 个单位长度时,就会停止前进。目前不知道两位勘探员谁先出发,只知道他们各自从两端相向而行向中间靠拢,中间相隔 k k k 个位置的时候停止勘探。问这块数轴地可能最小的宝藏辐射值是多少?

题目的意思很明确了,也即从左往右 + 从右往左各来一次最大值最小值前后缀计算,求每个位置其左侧和右侧的前缀/后缀最大最小值,然后中间隔 k k k 个位置,用左右两侧的最小值作为实际最小值,左右两侧的最大值作为实际最大值,此时计算一次最大值减去最小值并维护更新答案。滑窗一遍即可计算出来。

比如前缀 [ 0 , x ] [0, x] [0,x] 的最小值和后缀 [ x + k + 1 , n ] [x+k+1,n] [x+k+1,n] 的最小值,取其小者;前缀 [ 0 , x ] [0, x] [0,x] 和后缀 [ x + k + 1 , n ] [x+k+1,n] [x+k+1,n] 的最大值取其大者。此时就是一种勘探员互相停止的情况,计算这种情况下的辐射值,维护更新一次答案,然后把中间这块长度为 k k k 的禁区滑窗右移,再次通过两侧取最大最小值计算辐射差值,继续维护更新,直到滑窗完成。

3. 心智能力

小明小红两个人进行记忆和心算能力测试,两个人各自脑海中有一个初始化为全零长度为 n n n 的数组,互相对对方的某个指定区间做加减修改(不会是差分数组或者线段树吧?),但是发现太容易了,于是加大难度。现在对对方的某个区间进行统一增加/减少修改时,需要指定对值为奇数还是偶数的值做操作(注意不是下标的奇偶性,而是值的奇偶性),小明觉得有点难度了,请你帮他设计一个程序完成小红的挑战。

寄,没思路,感觉线段树也用不上了,差分数组或者前缀和也不是,都试过了全部超时,感觉应该是有其他正确的解法,或者我没见过的数据结构。一开始写的暴力方法,一个数组额外记录每个位置上值的奇偶性,然后操作的时候,根据奇偶数的加法更新区间内每个值的奇偶性,同时只有奇偶性匹配的值才会做修改。这里我用位运算稍微优化了一下,不过也就优化了几百毫秒,我的方案整体用时 11 秒,优化微不足道。位运算优化就是异或来更新奇偶性,毕竟异或的话 同为零,异为一 ,同时奇偶数加减法又有以下规律:

  1. 奇数 与 奇数 得 偶数
  2. 奇数 与 偶数 得 奇数
  3. 偶数 与 奇数 得 奇数
  4. 偶数 与 偶数 得 偶数

,现在我们要让这个性质成为加法的乘一系数(也就是 a + b × [ 0 ∣ 1 ] a+b\times[0|1] a+b×[0∣1] ),这样就不用写 if-else 语句特判哪个元素符合操作的奇偶性了,毕竟 if-else 分支预测语句是很影响 CPU 的指令吞吐率的,能不用分支结构尽量不用分支结构。因此这里的需求是性质相同则系数为 1 1 1 ,性质不同则系数为 0 0 0 ,代表无效操作。那么还是可以用异或的,只不过变成了 同为一,异为零 罢了(题目中 1 1 1 表示奇数操作, 0 0 0 表示偶数操作,我的奇偶性数组就顺便和题目统一表示了吧),所以就是 1 − a ⊕ b 1-a \oplus b 1ab 反转一下即可。 当然最后还是超时,没有拿到分,寄。

4. 牌型分组

给定一副扑克牌,牌型分组的时候无需考虑花色。普通扑克牌一组 13 张,这里可以拓展为更普适的情况, n = x n=x n=x ,其中 x x x 可能到 500。扑克牌的每张牌有牌点,除了大小王,牌点最大的牌是 2,然后是 A A A ,然后是 [ n , … , 3 ] [n,\dots, 3] [n,,3] 。可以考虑的牌型如下

  1. 单张
  2. 对子(牌点相同的两张牌)
  3. 三张(牌点相同的三张牌)
  4. 顺子(牌点相同的五张牌)

其中对于顺子来说有一些特殊要求:

  1. 不能出现 [ … , 2 , A , … ] [\dots,2,A,\dots] [,2,A,] 的顺子,也就出顺子牌的时候 2 2 2 不能作为 A A A 的下一张
  2. 可以使用 [ 5 , 4 , 3 , 2 , A ] [5,4,3,2,A] [5,4,3,2,A] 顺子

尽可能地组多张牌的牌型打出去,求最后剩余的牌点严格比 A A A 小的单张牌数量。每行测试用例会包含一张牌的花色和牌点,用空格分离(花色没啥用吧其实?还是说我漏看了什么信息),大小王牌同样不设数量限制(大小王牌应该是只能通过三张和对子出掉了)。

没思路,没做出来,感觉是个大模拟题。但是也有一点规律,首先应该是要贪心的, 2 、 3 、 5 2、3、5 235 这三个数互质啊,是不是这三个牌型各自组各自的不怎么影响。那是不是能出顺子就出顺子,出完顺子再考虑三张,最后考虑对子,实在没有了就是出完了只剩单张了,不知道这个贪心思路对不对。

5. 资源分配

初始给定一组逻辑处理器数量和物理内存固定的物理机,现在要处理客户创建虚拟机的资源分配需求,要求实现:

  1. init(n, c, m) 表示初始化 n n n 台具有 c c c 个逻辑处理器以及 m m m GB 物理内存的物理机
  2. create(vid, vcpu, vmem) ,表示需要在有可用资源的物理机上创建一个虚拟机ID为 vid 的,需要 vcpu 个逻辑处理器以及 vmem GB 物理内存的虚拟机,如果资源不够(没有任何一台物理机的剩余量能够同时满足 cpu 和 mem 的需求),可以申请立刻扩容一台物理机加入到资源池再继续分配(所有物理机规格相同,和初始化时候的机器配置一样),返回值是一个二元组,表示虚拟机实际被分配到的物理机编号和是否扩容了一台物理机(题目说一次性最多可以扩容 500 台物理机,但是又强调一次虚拟机分配的资源不可能超过单台物理机的配置,那不就肯定每次最多扩容一台嚒,没懂,可能是混淆视听?)
  3. remove(vid) ,删除虚拟机ID为 vid 的虚拟机,将计算资源归还给对应的物理机

请使用尽可能少的物理机完成每个测试用例的虚拟机分配创建请求,测试数据给定一个已经实现的虚拟机分配算法作为基线算法,它在公开的 20 个测试样例中已经给出了由 baseline 分配算法通过测试样例所有虚拟机分配的最少的物理机数量,你的分配算法如果比 baseline 强可以得到额外的加分,加分是乘法系数,系数为 b a s e y o u r \frac{base}{your} yourbase ,也即你给出的所需物理机数量比 base 给出的数量越少,奖励倍数越大,最终本题得分由所有测试样例的平均分决定,满分 200 分。

物理机最多创建 5 × 1 0 5 5\times 10^5 5×105 台(忘记是不是这个数了,反正很大,测试样例实际运行出来的结果也很大)。每次申请的虚拟机的资源需求一定不会超过物理机的单机配置,也就是不会出现多台物理机的计算资源融合供给给一台虚拟机使用(大大降低了难度)。如果你的分配算法导致系统 OJ 检测到不合理的分配,比如在已经资源耗竭的物理机上继续分配虚拟机,测试会立即终止,并且该测试样例不得分。

其实类似 leetcode ,不过这里是一个完整的离线项目,需要本地 IDE 有多文件编译经验才行,我是本地随手写了个简陋的 CMakeLists 编译的。用户要求实现 Scheduler.cpp 文件中空白的函数体定义,配合 main.cpp 文件进行 benchmark 测试,离线的 20 个公开测试样例已经作为文本文件放在 data 目录下,main.cpp 运行时自动读取测试样例和基线答案,无需用户关心 IO ,用户只需要实现 Scheduler.cpp 在通过本地测试之后把 Scheduler.cpp 的内容粘贴到提交窗口提交评分即可。(不是,怎么这么一股国外数据库公开课 15445 味道啊,还要自己填充空的函数体交上去评分排名 rank ?)

有几种参考的思路:

  1. 直接爽开最大数量的物理机,来分配的虚拟机需求直接顺序分配物理机,爽。就是这么干基本是零分,因为得分系数是基线给出的最少需要的物理机数量和你的分配算法给出的物理机数量之比,你的数量要是太大了那 base 分子就会相对的很小。每题的基线分是 120
  2. 对资源池里面的物理机用 for-loop ,找到合适的物理机就分配资源,没有就扩容一台
  3. 使用操作系统级的资源分配算法,比如内存池中碎片最小的适应性分配算法,或者页面分配算法中的优先级队列,看你做到这题还剩多少时间。我选了个比较简单的二分优化找到第一台有至少满足资源的机器的方案

我觉得我的这种 FirstFit 方案就是基线方案,因为我交上去评分就是 120 分,和基线差不多,满分 200 分的方案肯定是用了什么数据结构的,有优先级的分配。

这题二分的话要注意,是基于两个指标来二分,cpumem ,因为平时 leetcode 写二分都是基于一个指标来写的,所以还折腾了一会(没搞懂具体原理,但反正工作结果是符合预期了,二分查找停止的位置能在两个资源指标都符合的时候才停止)。另外还需要考虑具体实现上存放物理机资源池的数据结构,物理机本身的 CPU 和 MEM 很简单,搞个结构体放两个 int 字段表示物理机的剩余资源就行,关键就是这个结构体在什么数据结构中,插入的时候自动就是按照 CPU 和 MEM 排序的。一开始我想用优先队列,发现优先队列是适配器不是容器,没有 begin()end() 迭代器,没法从数据结构中删除旧的物理机状态再插入新的物理机状态,所以放弃了。然后想到可以用 multiset ,可重复的集合中,元素是有序插入的,时间复杂度应该是 O ( n l o g n ) O(nlogn) O(nlogn) ,还能接受,查找删除定位的话,只需要每次在申请物理机的时候把物理机编号和插入 emplace 返回的迭代器记录在哈希表里面就行了,要修改物理机的状态的时候,直接从哈希表拿到迭代器把物理机状态从 multiset 里面拎出来(multiset.erase 删除掉旧状态),做完物理机资源的增加/减少再重新把状态插入回 multiset 排序。

multiset 因为有迭代器可以顺序遍历,因此是可以二分的,直接使用标准库 <algorithmn> 提供的 std::lower_bound 即可找到第一个资源大于等于虚拟机要求的物理机。但是 std::lower_bound 最好自己提供一个 lambda 比较函数,一次就定位到 cpu 和 mem 资源都符合的物理机上,如果是默认的 pair<int, int> 之类的什么二元组比较,可能第一个 cpu 资源满足了就停止查找了,然后你还得从停止的位置自己做线性 iter++ 往后找 mem 符合要求的物理机,也是很慢的。

其他细节的话就是还要保存虚拟机分配到哪个物理机的哈希表映射,这样 remove(vid) 的时候你才能根据 vid 找到对应的物理机 pidmultiset 里拿到状态。然后物理机资源状态是自定义结构体 struct 记得要开一个对应的结构体重载 operator() 作为比较运算子给 multiset 的模板参数,比如 std::multiset<type_rs, type_comp> ,其中 type_comp 是重载了 operator()(const type&, const type&) 负责比较两个物理机状态结构体的结构体。

create 的思路就是:

  1. 二分查找
  2. 迭代器指向末尾,没有合适的空闲机器,申请一台新的并把当前虚拟机分配到新的物理机上
  3. 迭代器指向有效位置,有合适的空闲机器,删除空闲物理机的旧状态,更新物理机分配资源给虚拟机,剩余资源减少的新状态,重新插入到 multiset
  4. 更新 “物理机-迭代器” 和 “虚拟机ID-物理机ID” 的哈希表映射

remove 的思路就是:

  1. 根据虚拟机ID得到物理机ID
  2. 删除物理机旧状态,更新物理机剩余资源得到新状态,新状态重新插入回 multiset
  3. 更新 “物理机-迭代器” 和 “虚拟机ID-物理机ID” 的哈希表映射

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/482228.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一体化数据安全平台uDSP 入选【年度创新安全产品 TOP10】榜单

近日&#xff0c;由 FreeBuf 主办的 FCIS 2024 网络安全创新大会在上海隆重举行。大会现场揭晓了第十届 WitAwards 中国网络安全行业年度评选获奖名单&#xff0c;该评选自 2015 年举办以来一直饱受赞誉&#xff0c;备受关注&#xff0c;评选旨在以最专业的角度和最公正的态度&…

pycharm链接neo4j(导入文件)

1.新建csv文件 2.写入文件 3.运行代码 import csv from py2neo import Graph, Node, Relationship# 连接到Neo4j数据库&#xff0c;使用Bolt协议 graph Graph("bolt://localhost:7687", auth("neo4j", "password"))# 读取CSV文件 with open(…

vscode ctrl+/注释不了css

方式一.全部禁用插件排查问题. 方式二.打开首选项的json文件,注释掉setting.json,排查是哪一行配置有问题. 我的最终问题:需要将 "*.vue": "vue",改成"*.vue": "html", "files.associations": { // "*.vue": &qu…

TCP三次握手与四次挥手(TCP重传机制,2MSL)超详细!!!计算机网络

本篇是关于3次握手和四次挥手的详细解释~ 如果对你有帮助&#xff0c;请点个免费的赞吧&#xff0c;谢谢汪。&#xff08;点个关注也可以&#xff01;&#xff09; 如果以下内容需要补充和修改&#xff0c;请大家在评论区多多交流~。 目录 1. TCP头部&#xff1a; 2. 三次握手…

单片机学习笔记 15. 串口通信(理论)

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

C#中switch语句使用

编写一个程序&#xff0c;使用switch语句将用户输入的分数转换成等级&#xff0c;如表 private static void Main(string[] args) { Console.WriteLine("请输入分数&#xff1a;"); int score int.Parse(Console.ReadLine()); switch (score) …

[网络安全]sqli-labs Less-5 解题详析

[网络安全]Less-5 GET - Double Injection - Single quotes - String:双注入GET单引号字符型注入 判断注入类型判断注入点个数查库名&#xff08;爆破&#xff09; left函数抓包查库名&#xff08;双查询注入&#xff09; 原理实例查库名&#xff08;extractvalue函数&#xff…

pyspark实现基于协同过滤的电影推荐系统

最近在学一门大数据的课&#xff0c;课程要求很开放&#xff0c;任意做一个大数据相关的项目即可&#xff0c;不知道为什么我就想到推荐算法&#xff0c;一直到着手要做之前还没有新的更好的来代替&#xff0c;那就这个吧。 推荐算法 推荐算法的发展由来已久&#xff0c;但和…

python股票数据分析(Pandas)练习

需求&#xff1a; 使用pandas读取一个CSV文件&#xff0c;文件内容包括股票名称、价格和交易量。完成以下任务&#xff1a; 找出价格最高的股票&#xff1b; 计算总交易量&#xff1b; 绘制价格折线图。 代码实现&#xff1a; import pandas as pd import matplotlib.pyplot …

利用Python爬虫精准获取淘宝商品详情的深度解析

在数字化时代&#xff0c;数据的价值日益凸显&#xff0c;尤其是在电子商务领域。淘宝作为中国最大的电商平台之一&#xff0c;拥有海量的商品数据&#xff0c;对于研究市场趋势、分析消费者行为等具有重要意义。本文将详细介绍如何使用Python编写爬虫程序&#xff0c;精准获取…

K8s调度器扩展(scheduler)

1.K8S调度器 筛选插件扩展 为了熟悉 K8S调度器扩展步骤&#xff0c;目前只修改 筛选 插件 准备环境&#xff08;到GitHub直接下载压缩包&#xff0c;然后解压&#xff0c;解压要在Linux系统下完成&#xff09; 2. 编写调度器插件代码 在 Kubernetes 源代码目录下编写调度插件…

领养我的宠物:SpringBoot开发指南

第2章 开发环境与技术 本章节对开发宠物领养系统需要搭建的开发环境&#xff0c;还有宠物领养系统开发中使用的编程技术等进行阐述。 2.1 Java语言 Java语言是当今为止依然在编程语言行业具有生命力的常青树之一。Java语言最原始的诞生&#xff0c;不仅仅是创造者感觉C语言在编…

Permute for Mac 媒体文件格式转换软件 安装教程【音视频图像文件转换,简单操作,轻松转换,提高效率】

Mac分享吧 文章目录 Permute for Mac 格式转换软件 效果图展示一、Permute 格式转换软件 Mac电脑版——v3.11.15⚠️注意事项&#xff1a;1️⃣&#xff1a;下载软件2️⃣&#xff1a;安装软件2.1 左侧安装包拖入右侧文件夹中&#xff0c;等待安装完成&#xff0c;运行软件2.2…

【Android】EventBus的使用及源码分析

文章目录 介绍优点基本用法线程模式POSTINGMAINMAIN_ORDEREDBACKGROUNDASYNC 黏性事件 源码注册getDefault()registerfindSubscriberMethods小结 postpostStickyunregister 介绍 优点 简化组件之间的通信 解耦事件发送者和接收者在 Activity、Fragment 和后台线程中表现良好避…

原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder

原子类 JDK提供的原子类&#xff0c;即Atomic*类有很多&#xff0c;大体可做如下分类&#xff1a; 形式类别举例Atomic*基本类型原子类AtomicInteger、AtomicLong、AtomicBooleanAtomic*Array数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArrayAtomic…

【Electron学习笔记(三)】Electron的主进程和渲染进程

Electron的主进程和渲染进程 Electron的主进程和渲染进程前言正文1、主进程2、渲染进程3、Preload 脚本3.1 在项目目录下创建 preload.js 文件3.2 在 main.js 文件下创建路径变量并将 preload.js 定义为桥梁3.3 在 preload.js 文件下使用 electron 提供的contextBridge 模块3.4…

FFmpeg一些常用的命令

官网&#xff1a;https://ffmpeg.org/ 官网下载&#xff1a;https://ffmpeg.org/download.html 官网下载源码&#xff1a;https://www.ffmpeg.org/releases/ FFmpeg 实用命令 — FFmpeg 教程 文档 一、参数 1.1 FFmpeg 常用参数 参数说明备注-i filename指定输入文件&#…

JAVA篇08 —— String类

欢迎来到我的主页&#xff1a;【一只认真写代码的程序猿】 本篇文章收录于专栏【小小爪哇】 如果这篇文章对你有帮助&#xff0c;希望点赞收藏加关注啦~ 目录 1 String概述 1.1 String特性 1.2 String常用方法 2 StringBuffer类 2.1 String与StringBuffer互转 2.2 Stri…

Flink四大基石之Time (时间语义) 的使用详解

目录 一、引言 二、Time 的分类及 EventTime 的重要性 Time 分类详述 EventTime 重要性凸显 三、Watermark 机制详解 核心原理 Watermark能解决什么问题,如何解决的? Watermark图解原理 举例 总结 多并行度的水印触发 Watermark代码演示 需求 代码演示&#xff…

LabVIEW将TXT文本转换为CSV格式(多行多列)

在LabVIEW中&#xff0c;将TXT格式的文本文件内容转换为Excel格式&#xff08;即CSV文件&#xff09;是一项常见的数据处理任务&#xff0c;适用于将以制表符、空格或其他分隔符分隔的数据格式化为可用于电子表格分析的形式。以下是将TXT文件转换为Excel&#xff08;CSV&#x…