
简介面向蓝桥杯竞赛选手的题库合集已针对青岛大学QDUOJ在线评测系统完成优化适配适合需要在特定OJ环境中集中练习、验证算法代码的备赛者尤其适用于参加蓝桥杯全国编程竞赛的大学生和算法爱好者覆盖从基础巩固到拔高训练的多种题型。压缩包共2个文件一个JSON数据文件存储历年题目的描述、输入输出规格、时间与内存限制等结构化信息数据格式清晰便于解析、检索与批量导入一个ZIP测试用例包收录配套的输入输出样例解压后可直接导入QDUOJ进行代码提交、结果比对和调试排错。整个包体约70.24MB体量适中易于下载部署。目前已有1363人浏览学习。这一修改版对题目数据格式和评测配置进行了适配可减少格式不兼容带来的报错。资源涵盖历年蓝桥杯赛题及样例数据能帮助使用者系统熟悉题型、理解在线判题规则并通过反复模拟测试强化算法设计与程序实现能力为备赛冲刺和技能进阶提供有效支撑。1. 蓝桥杯题库 for QDUOJ一份修改版资源解决的是“导入即翻车”的兼容性问题备考蓝桥杯的编程训练绕不开一个老问题历年真题散落在各大OJ上而自己搭的QDUOJ一套基于Django的开源在线评测系统默认并不识别蓝桥杯官方的题面格式。直接下载网上流传的蓝桥杯题库包导入后台大概率遇到题面乱码、测试数据不匹配、插图全部挂掉这类问题。这份蓝桥杯题库 for QDUOJ修改版的价值在于它把题面拆成了OJ支持的独立字段把测试数据按输入输出成对放好图片资源也统一规划了路径导入后能直接用来训练和组模拟赛。适合正在维护OJ、想给训练队补蓝桥杯真题的人也适合刚搭好OJ、不想在兼容性上耗三天的新手管理员。2. 拆包与结构目录怎么排、字段怎么填修改版到底改了什么2.1 解压之后的目录长什么样我第一次解压这份修改版时第一个感觉是“这次整理得算规矩”最外层是一个主目录主目录下分了 problems 和 images 两个子目录。problems 下面按题目序号和专题命名比如 001-入门训练-序列求和、002-基础练习-十六进制转八进制 这种结构。images 目录集中存放题面里引用的插图不再散落在各个题目目录里方便后续做路径重定位。再往下一层每道题是一个独立目录里面包含一个题目描述文件一般叫 problem.json、一个样例文件samples.json以及一个 data 目录。data 目录里是评测机真正要用的标准输入输出文件命名方式是 input-1.txt、output-1.txt 成对出现。拿到压缩包的第一步我建议先做完整性检查而不是直接解压导入unzip -t lanqiao_mod.zip | tail -3这条命令会遍历zip包内的所有文件并计算校验值末尾三行是总结会给出“No errors detected in compressed data”或者具体损坏文件列表。这一步能避免解压到一半发现某个题目目录损毁再回去重新下载的时间浪费。接下来再解压并确认 data 目录下没有 macOS 系统自动生成的 .DS_Store 文件如果有先清掉再导入否则导入脚本有可能把这类隐藏文件当成数据文件处理。解压后我还习惯用一条命令统计题目目录数和数据目录数是否一致find problems -mindepth 1 -maxdepth 1 -type d | wc -l find problems -mindepth 2 -maxdepth 2 -type d -name data | wc -l两条命令的数字应该相等差一个都说明有题目缺测试数据这时候留在导入前修会比导入后再一道题一道题排查划算。我知道有人觉得这个步骤多余但我后来吃过一次亏一道递归专题的题目 data 目录是空的导入后每次判题都在评测队列里挂起排查了好久才发现是缺了数据目录。2.2 题面字段QDUOJ认识什么格式QDUOJ 的题目模型在后台是可以手工编辑的但批量导入依赖的是一份约定好的 JSON 结构。这份修改版里每个题目目录下的 problem.json 就是核心文件字段分成两批一批是展示字段一批是评测字段。展示字段决定了选手在题面页看到什么评测字段决定了判题行为。下面是我整理过的字段清单字段名类型说明titlestring题目标题descriptionstring题面正文支持 Markdown 语法input_descriptionstring输入格式说明output_descriptionstring输出格式说明sampleslist样例对每个样例含 input 和 outputtime_limitint单组测试数据的运行时间上限单位秒memory_limitint内存上限单位 MBtagslist标签列表导入时会创建或关联标签对象difficultyint难度等级一般取 1 到 10这套结构里最容易在转换时丢信息的是 input_description 和 output_description 两个字段。网上很多题库包把输入输出说明、数据范围、样例提示全部拼进一个 description 字段导入虽然不会报错但题面页只有一大块文字选手看“输入格式”要往下翻好几屏。修改版做的主要工作之一就是把官方题面按这三个区域拆分。拆分的标准也没有多么玄学我翻了几个文件后总结出的规律是蓝桥杯官方题面里“问题描述”“输入格式”“输出格式”“样例输入”“样例输出”“数据规模与约定”这几个标题是固定出现的。转换时按标题切分再把“样例输入”“样例输出”抽出来填进 samples 字段。有一点要留意samples 里的 input 文本往往以换行结尾QDUOJ 前台渲染时如果样例输入框末尾带换行有的浏览器会默认显示多一条空行视觉上有点怪但评测不受影响。想整齐一点的话可以在转换脚本里对 samples 文本做一次 strip()。下面是这个修改版里某道题的 problem.json 片段字段和上面的表格一一对应{ title: 序列求和, description: 求 123...n 的值。\n\n**输入一个整数 n**输出对应的和。数据规模保证 n 不超过 1000000000。, input_description: 输入包括一个整数 n。, output_description: 输出一行包括一个整数。, samples: [ { input: 5, output: 15 } ], time_limit: 1, memory_limit: 256, tags: [入门训练, 模拟], difficulty: 1 }代码里的 \n 表示 Markdown 换行QDUOJ 前台开启 Markdown 渲染后会自动转成段落。tags 里写的中文标签导入程序会先去标签表里查同名标签不存在就新建这也是修改版对原始题库做的一层整理。原始版本里很多题目没有打标签导入后题面虽然正常但筛选分类时找不到入口等于题库少了一半价值。2.3 从 HOJ 结构转过来转换脚本的核心逻辑网上流传的蓝桥杯题库相当一部分绑定了某个常用OJ课题工程的导入格式社区里常简称为 HOJ。它的JSON字段是 problem_title、problem_description 这种下划线风格样例放在 input_value、output_value 这种字段里还混入了一些该OJ特有的统计字段比如 total_submit。如果直接把这种结构交给 QDUOJ 导入通常会报“未知字段”或者导入后字段静默丢失题面里只剩下半个标题。修改版的转换思路是读一遍原始HOJ格式把字段按映射关系重命名将那个OJ特有的字段全部丢掉再补齐 QDUOJ 需要的默认值最后连同 data 目录一起整体打包。下面是一个简化版的转换脚本逻辑和修改版用到的思路基本一致import json import shutil from pathlib import Path src Path(hoj_problems) dst Path(qduoj_problems) field_map { problem_title: title, problem_description: description, input_format: input_description, output_format: output_description, } for item in src.glob(*/problem.json): data json.loads(item.read_text(encodingutf-8)) new_data {new: data[old] for old, new in field_map.items() if old in data} new_data.setdefault(samples, []) new_data.setdefault(time_limit, 1) new_data.setdefault(memory_limit, 256) new_data.setdefault(tags, []) new_data.setdefault(difficulty, 1) out_dir dst / item.parent.name out_dir.mkdir(parentsTrue, exist_okTrue) (out_dir / problem.json).write_text( json.dumps(new_data, ensure_asciiFalse, indent2), encodingutf-8, ) data_src item.parent / data if data_src.exists(): shutil.copytree(data_src, out_dir / data, dirs_exist_okTrue)这段脚本最核心的是 field_map 映射和 shutil.copytree 两行。field_map 负责把 HOJ 风格字段名改成 QDUOJ 风格copytree 负责把测试数据原样带过去。这里有一个我第一次写转换脚本时踩过的坑只做了字段映射忘了复制 data 目录导入后每道题都能正常打开但评测时全部报“没有测试数据”。排查了半天才发现是数据目录压根没有进新包。另外要说的是图片资源重定位。蓝桥杯官方题面里的插图是相对路径比如 images/fig1.png而 QDUOJ 展示题面时是在网页里渲染相对路径会直接指向题目页本身导致图片404。修改版里常见的处理方式是把图片统一收集到总目录下的 images 文件夹然后把 problem.json 里 description 中的图片引用改成类似 /media/lanqiao/fig1.png 的绝对路径这一步在转换脚本里可以加一段正则替换import re desc new_data[description] desc re.sub(rimages/([\w\-]\.png|[\w\-]\.jpg), r/media/lanqiao/\1, desc) new_data[description] desc正则替换时我会保守一点只替换图片扩展名。也有人直接把整段相对路径替换成完整线上域名但如果OJ的域名后续变了那些图片就全挂了所以建议先用 /media/ 这种应用内路径方便日后迁移。3. 导入这台OJ备份、导入、核对三步走3.1 导入前必须做的备份我导入任何题库包之前都会先备份当前OJ的数据库。QDUOJ 底层是 Django 应用数据主要存在数据库里最直接的方式是 mysqldumpmysqldump -u root -p --databases oj_db oj_backup.sql这里的 oj_db 是OJ库名以你服务器上的实际配置为准。如果你部署时用的是 PostgreSQL那对应的命令是 pg_dump常见写法为pg_dump -U postgres oj_db oj_backup.sql备份这一步不建议跳过因为题库导入会涉及题目表、标签表、题目-标签关联表多张表一起写中途失败就可能出现半截数据。真要是导入导到一半崩了备份就是唯一的后悔药。接下来确认当前OJ的版本和已装的依赖。登录服务器进入项目所在目录执行python manage.py --version pip show django-import-export | head -2不同分支的 QDUOJ 功能差异比较大有的自带“题目导入”后台按钮有的必须走管理命令还有的老版本压根没提供批量导入通道只能写脚本调Django ORM。所以备份后先确认版本再决定走哪条导入路径能省掉很多无效操作。3.2 两条导入路径后台操作与命令行路径一后台导入。登录QDUOJ管理后台进入题目列表页找到“导入题目”入口选择修改版压缩包后提交。这个方式适合题目量在十道以内的情况因为一次只能选一个文件导入过程没有进度条题库包一大于几十MB就很容易卡在等待状态。后台导入真正的好处是界面自带错误提示能把导入失败的原因显示在页面上适合第一次接触这个OJ的人先跑通流程。路径二命令行导入。这是我最常用的方式题库量大时方便脚本化操作。先把修改版压缩包解压然后进入QDUOJ项目目录执行下面的命令常见做法具体命令名以你自己的项目里 manage.py 支持的为准python manage.py import_problems --zip ./lanqiao_mod.zip --owner admin --visible false各参数的作用是--zip 指定要导入的压缩包路径--owner 表示题目的归属用户一般写管理员账号--visible 控制导入后题目是否为可见状态我先设成 false等核对完再统一改 true避免题目导入后立刻被训练队看到一堆半成品。如果你的项目里没有 import_problems 这个管理命令可以先确认是不是这个库的另一个分支实现。直接搜一下源码即可grep -rn import_problems --include*.py .搜索出来没有结果说明这个分支没有提供批量导入命令需要退回后台导入或者写一个小的管理命令直接调用项目里的题目模型创建记录。我不建议改数据库表结构来硬塞数据因为QDUOJ 的表结构里有些自增主键和关联字段手工插数据很容易破坏关联完整性。还有一个容易被忽略的细节如果压缩包内是嵌套目录比如 lanqiao_mod/2024/problems/xxx 这种导入脚本可能会找不到题目文件。常见处理方式是在导入前先重新打包把 problems 和 images 提升到压缩包根目录unzip lanqiao_mod.zip -d /tmp/lanqiao cd /tmp/lanqiao zip -r ../lanqiao_flat.zip problems images重打包的原因是导入脚本通常只扫描压缩包第一层目录嵌套过深时要么全部漏掉要么报压缩包格式错误。这一步很基础但确实是很多人第一次导入失败的原因之一。注意重打包时最好保持 zip 格式部分 QDUOJ 分支对 tar 包的支持并不完整压缩格式选稳妥的 zip 能少踩一个坑。3.3 导入后的核对清单导入完成后第一件事是核对题目数量。我先解压一份原始包用脚本统计题目目录数再和后台列表对比。统计脚本的逻辑是遍历每个题目目录检查里面的 data 目录是否存在、输入输出文件是否成对from pathlib import Path root Path(lanqiao_mod/problems) data_dirs list(root.glob(*/data)) pair_ok [] broken [] for data_dir in data_dirs: ins sorted(data_dir.glob(input-*.txt)) outs sorted(data_dir.glob(output-*.txt)) if ins and outs and len(ins) len(outs): pair_ok.append(data_dir.parent.name) else: broken.append(data_dir.parent.name) print(f配对正常的题目: {len(pair_ok)} / {len(data_dirs)}) print(存在问题的题目:, broken)脚本的判断标准是输入输出文件数量相等且不为空。输出文件数量比输入多说明有冗余数据输入比输出多说明缺判题标准答案。这两种情况在导入后都会造成评测异常。跑完脚本再随机挑两三道题在后台打开题面对照原始蓝桥杯官方页面的描述内容是否一致重点看输入输出样例的空白字符。如果样例文本里有肉眼分辨不出的差异选手会直接把题目当成坑题。导入后还有一个容易被忽略的点题目记录的缓存刷新。QDUOJ 有缓存机制导入后第一眼看到的列表可能是旧缓存如果立即编辑题目设置某些分支会先读缓存导致改动不生效。常见做法是导入后强制清理缓存或者等待定时任务刷新。命令行导入的题目一般会直接触发缓存清理后台导入的则不一定。遇到改完不生效的情况先别怀疑数据库清缓存往往能解决。4. 参数校准时限、内存、评测并发的调整边界4.1 不同语言组别的参数映射蓝桥杯按编程语言分成C/C组、Java组、Python组同样是“求最大公约数”三个组别的运行时限和内存上限往往不一样。修改版题库默认给的 time_limit 和 memory_limit 是按C组的尺度做的面向其他语言训练时就需要批量调整。常见做法是如果训练队主攻Java就把内存限制上调到512MB时间限制乘1.5主攻Python的话时间限制乘2、内存限制也建议给到512MB。原因很简单Python解释器启动和垃圾回收的额外开销比编译型语言大不少同样的算法在C里跑0.5秒到Python里可能就超2秒了。调整可以靠数据库批量更新但不同分支的表名和字段名有差异下面这条SQL是一个示意UPDATE oj_problem SET time_limit time_limit * 2, memory_limit 512 WHERE tags LIKE %Python组%;如果你不想动数据库也可以在QDUOJ后台用过滤器筛出Python组题目然后逐道修改。题目量少时后台改更直观题目量大了还是SQL来得快。调整后建议抽两三道典型题提交一次正确代码确认新参数不会把正常AC的代码卡成TLE。这一步相当于给整个题库做一次抽样回归别省。参数调整边界的判断有个经验值time_limit 降到0.3秒以内的题目只适合专门练常数优化不适合日常训练memory_limit 给到1GB以上对蓝桥杯真题来说又太富裕起不到对极端数据处理的约束作用所以修改版里默认的C组 1秒/256MB 和已经调整过的 Python 组 2秒/512MB已经覆盖了大多数场景。4.2 浮点输出与Special Judge的取舍蓝桥杯部分题目要求输出浮点数且明确写了“与标准答案误差不超过1e-6”。默认的逐字节比较在这种题上必然误判。修改版题库里这类题目会在 problem.json 里带 judge_type 字段常见值有 default、spj、compare。导入之后你要确认这些浮点题的 judge_type 是 spj 而不是 default。判断一道题是否需要开 spj标准很简单看输出描述里有没有“保留两位小数”“误差不超过”“四舍五入”这些表述有的话基本都要开。开了 spj 之后评测机在判题时会去测试数据目录里找 spj 程序常见命名是 spj 或 check。如果 spj 程序没放到位评测机会直接报“judge not found”而不是正常WA。一个比较常见的误判场景是这样的选手在本地测样例输出是 0.33333333评测机要求的是 0.33逐字节比对直接WA。开了 spj 之后评测程序只比较两个数的差是否在指定误差范围内这道题才算是真正能用。所以导入后专门留出几分钟翻一遍浮点题比之后接到大量用户反馈再排查省时间。4.3 沙箱并发与资源上限题库导完后短期提交量往往会有一个明显抬升。QDUOJ 的评测服务是独立组件并发上限不在题库本身而取决于评测机资源和沙箱配置。如果沙箱内存上限设得比题目 memory_limit 还小评测进程就会在题目限时之前被系统杀掉表现成“用户AC代码提交后直接空包”。这是那种很难肉眼定位的问题因为它只在并发高的时候偶发复现需要靠运气。我一般会先确认这几个参数再放线上参数建议值说明评测并发进程数2-4大于8后容易出现评测队列积压与偶发超时沙箱单进程内存上限1024MB低于题目要求的512MB会出现诡异MLE评测临时目录空间10GB以上编译现场包含选手源码、编译产物与测试数据这几个数字不是放之四海而皆准但适合大多数单机部署场景。如果评测机内存只有4GB并发进程数建议压到2如果是16GB内存的机器可以适当放到6。沙箱参数调完以后需要重启评测服务才能生效这个重启动作常被忘掉改完配置不重启等于没改。最稳妥的做法是改完临时目录、沙箱和并发参数后提交几道简单题确认评测流程正常再开放题库。5. 避坑手册导入蓝桥杯题库的五次真实翻车现场5.1 题面里的图片全部挂掉现象导入后题目能显示但题面里的图片要么显示成裂图要么直接变成一行图片路径文本。原因修改版把图片集中放在 images 目录但问题描述里引用的还是相对路径比如 images/fig1.png。QDUOJ 在网页端渲染时相对路径会基于当前题目URL去解析自然找不到文件。解决先把 images 目录整体拷贝到 OJ 的媒体目录下比如 media/lanqiao/images。然后写一段脚本把 problem.json 中 description 里出现的相对图片路径全部替换成 /media/lanqiao/images/xxx.png 这种绝对路径替换完清一遍浏览器缓存随机打开几道题确认图片加载正常。这次之后我把“图片路径重定位”加进了自己的标准转换流程再没犯过同样的错。5.2 样例能过但提交后被判WA现象选手在本地运行样例输入输出和题目完全一致提交到OJ后却被判WA。原因测试数据里的 output 文件末尾多了一个空格或换行。QDUOJ 默认的 compare 模式是逐字节比较差一个空格也算错。解决统一清洗 output 文件的行尾空白。我一般用 sed 处理sed -i s/[[:space:]]*$// data/output-*.txt这条命令会去掉每行末尾的空白字符但保留换行。清洗后重新导入或者如果只是改了数据文件直接重启评测服务让新数据生效也行。这种坑最气人的是题目描述看着完全正常只有评测机在暗地里卡人。5.3 Python组内存超限本地却完全不超现象选手提交的Python代码在自己电脑上能跑内存占用也不高到OJ上一跑就MLE。原因导入包里Python题目的 memory_limit 沿用C组的256MB。Python解释器本身有基础内存开销再加上递归栈和大数组很容易突破256MB。本地开发机内存占用和沙箱里统计方式也不完全一致所以本地不超、线上超是常态。解决批量把Python组题目内存上限调到512MB时间限制乘2。调完重新提交之前MLE的代码做回归能过就是正常。这种问题单纯调平台全局参数解决不了必须分题目调因为C组题目如果也调到512MB就失去了练内存精度的意义。5.4 导入后题面变成一整块纯文本现象题面所有段落都挤在一起没有换行和标题层级读起来特别费劲。原因修改版描述文件用的是Markdown换行但 QDUOJ 后台这个版本的编辑器默认按HTML渲染Markdown语法没有被解析所以所有换行变成了空格。解决在后台开启题面的Markdown渲染开关或者导入前把Markdown软换行转成HTML的标签。这两种做法选一个即可。我更倾向在导入流程里直接转换这样无论哪个QDUOJ分支都能显示正常不用每个环境都去调一次后台开关。5.5 导入后题目分类全部丢失现象题库倒进去了但标签列表是空的所有题目堆在未分类区域。原因原始HOJ格式里根本没有 tag 字段转换脚本里 setdefault(tags, []) 给了一个空列表导入后自然没有分类可关联。解决先到后台手动创建“入门训练”“基础练习”“历届试题”“决赛”这几个稳定分类然后写一个小脚本根据题目目录名前缀比如 001-入门训练-xx去匹配标签并重新关联。虽然要额外花点时间但分类建好后后续按专题训练、按难度出模拟赛都能靠标签筛选。6. 进阶用法把题库变成训练赛与报告生成器的配套资源题目导入只是第一步QDUOJ里最出效果的用法是把这些题挂进比赛。常见做法是在后台新建一场比赛模式选ACM把修改版题库里按难度或年份筛出的题目拖进比赛题目列表时长设三小时打开实时排行榜。这样一来每周一次的模拟赛都能沉淀出提交数据而不是让题目躺在题库里吃灰。比赛结束后我习惯跑一段从数据库导出提交统计的脚本按用户名和题目分组统计AC数、提交次数、通过率生成一份简易训练报告。核心逻辑大致如下from collections import defaultdict subs [...] # 已从submission表读取的记录 user_ac defaultdict(int) user_submit defaultdict(int) for sub in subs: if sub.result AC: user_ac[sub.username] 1 user_submit[sub.username] 1 for name in sorted(user_ac): print(name, user_ac[name], user_submit[name])这段脚本不复杂但配合分类标签很快能看出全队在“基础练习”和“算法提高”两类题目上的表现差异比人工翻榜单高效得多。另一个常用技巧是按标签导出题目的子集。比如只导出“递归”专题到测试服验证可以写个遍历 problem.json 的小脚本过滤 tags 包含“递归”的题目重新打包。这样临时环境就不用每次往线上导全量题库避免把测试数据留在生产库。现在我的固定流程是导入题库前先在一台临时实例上完整跑一遍备份、导入、核对、挂测四步确认题目展示和评测都正常再动线上。从那以后我再没出现过题库导入把线上OJ搞挂的情况。希望帮到你。本文还有配套的精品资源点击获取