拓冰建站拓冰建站
首页 / 资讯中心 / 正文

杭电OJ刷题指南:从A+B到Accepted的完整路线与避坑技巧

简介杭州电子科技大学OJ题库离线HTML快照适合编程初学者、算法爱好者及ACM/ICPC备赛者使用。压缩包内共5743个html文件整体大小53.36MB每个文件以题目ID命名对应题库中的具体题号涵盖排序、搜索、图论、动态规划等经典算法专题。打开这些页面即可查看题目描述、输入输出格式、样例测试与解题要求无需联网也能随时查阅和练习。已有2123人学习下载轻量且便于按ID检索既能用作日常刷题的题目清单也可用于集中突破某一类算法。通过逐题研读与代码实现可系统训练编程思维、提升调试能力和竞赛解题速度为笔试面试或程序设计竞赛打下扎实基础。1. 杭电OJ题库是什么刷题不只是攒Accept数量刚接触ACM的选手十个里有八个会把“杭电OJ”当成一个刷题计数器比谁交的题多、比谁颜色深。但杭电OJHDU Online Judge题库真正值钱的地方是那套从易到难的梯度设计——从最基础的AB一路做到DP、后缀自动机、网络流每一档都有大量可练的题。你从第1000题开始刷刷到1000题以上时基本就把竞赛里最常见的几类算法过了一遍。适合两类人一是刚打ACM想找稳定训练场的新手二是想赛后补题却不知道去哪找题源的老手。这题有一个其他平台比不了的特点——题目轻量、数据稳、不用开会员而且老题多套路齐全。这篇文章就把从注册到拿Accept的全过程拆开讲包括判题规则、提交格式、刷题路线和最容易翻车的几个坑。2. 在杭电OJ上跑通第一道题注册、编译器选择与判题机制2.1 注册与编译器版本为什么C要选G而不是MS C杭电OJ的注册页没有太多复杂选项用户名、邮箱、密码就够了。提交代码时会遇到第一个关键选择——编译器。常见的有G、GCC、MS C、Java、Python。我一般只选G因为杭电的评测机是Linux环境G对应的就是Linux下的g命令头文件、内存对齐、栈大小都和比赛环境一致。MS C走的是Windows下的VC编译器部分标准库实现不一样比如在%I64d和%lld的处理上就容易出问题。如果你有在Windows本地用Visual Studio调试的习惯提交前一定记得把代码切到G再交否则可能同一个逻辑本地跑得好好的交上去就是WA。注册完之后先别急着开刷去Problem Archive里找到1000题AB Problem把那一行提交框用起来。这道题的作用不是让你学算法是让你确认整个提交链路是通的本地编译、上传代码、评测机返回结果、看到绿色的Accepted。我第一次给学弟讲的时候总让他们先交1000题不为别的就为了先排除“自己连提交都不会”这种最尴尬的情况。2.2 判题结果解读Accept之外还有哪些状态点提交之后评测机返回的状态大概有七种看清每一种的含义比盲目改代码重要得多Accepted (AC)通过。但AC不代表你的代码最优只代表这组数据下没出问题。Wrong Answer (WA)答案不对。可能是思路错也可能是格式错后面会专门讲。Presentation Error (PE)几乎和AC一样但多了一个空格或者空行。这个状态特别可惜改一下格式就能过。Time Limit Exceeded (TLE)超时。杭电的题目会在标题旁边标Time Limit一般是1000MS或2000MS你的算法复杂度太高了。Memory Limit Exceeded (MLE)超内存。多半是数组开太大或者递归层数太深栈溢出。Runtime Error (RE)运行期错误。数组越界、除零、栈溢出、野指针都归这一类。Compile Error (CE)编译错误。点开能看到编译日志大多数是头文件漏了或语法小问题。这里有个刚刷题的人不知道的规律杭电的评测机很快同样的算法在别的OJ能过的在杭电不一定能过反过来杭电AC的代码拿去其他OJ多数也能过。因为杭电的数据偏“强”很适合用来检验算法的稳定性。如果你提交后看到TLE不要急着加#pragma优化先看一眼算法复杂度是不是本来就不该过。2.3 本地编译环境搭建MinGW还是Visual Studio代码最终在评测机上编译运行但你在本地得先有一套能用的环境。常见选择是Code::Blocks配MinGW或者直接用Visual Studio再或者装个VS Code配mingw-w64。我自己的使用习惯是本地不管用什么写提交前一定用命令行编译一遍。为什么因为IDE有时候会自动帮你补头文件或者用了MS的扩展语法到了评测机上g不认。你至少要有一次在命令行里敲g main.cpp -o main成功的经验才有资格说“我能在杭电上稳定刷题”。g -stdc11 main.cpp -o main -O2 -Wall-stdc11指定标准杭电的G版本支持C11但个别老的编译器配置可能不支持更激进的特性所以保守一点用C11就好。-O2是评测机默认的优化级别本地开同样的优化能提前暴露一些依赖未定义行为的代码比如数组越界读这种在-O0下可能侥幸跑对-O2下直接崩掉。-Wall会输出警告看到警告至少要扫一眼很多RE都是因为没读警告。3. 拿Accept的正确姿势输入输出格式、算法模板与复杂度估算3.1 输入输出格式EOF、多组数据与输出“Case #x:”杭电OJ的题目输入输出格式比洛谷要传统得多。很多题是多组测试数据直到读到EOF才结束。最常见的一个坑是新人用scanf读单个值读不到就以为出错了实际上判断EOF应该用scanf(%d, n) 1来作为循环条件。还有一种很常见的输出格式要求Case #x: answer这里的#有没有、:后面有没有空格必须照着题目原文写多一个空格就是PE甚至WA。#include cstdio int main() { int a, b, cas 0; while (scanf(%d %d, a, b) 2) { printf(Case %d: %d\n, cas, a b); } return 0; }这里的scanf返回值是成功读入的参数个数等于2说明两个整数都读到了。等于0或EOF就退出循环。cas是典型的竞赛写法先自增再输出省掉一行初始化。这类输入输出格式在杭电前100道题里会反复出现写熟练之后形成条件反射后面读题才知道重点在算法上而不是IO上。3.2 常用算法模板GCD、快速幂、素数筛刷到中期你会发现杭电的题特别喜欢在包装上做文章但内核永远是那几类基础算法。我建议你准备一个自己的代码模板库把高频算法写成函数每次直接调用。别一开始就背代码先把思路理解了再整理成自己的模板。以下是我的模板库里出镜率最高的三段// 最大公约数辗转相除法 int gcd(int a, int b) { return b 0 ? a : gcd(b, a % b); } // 快速幂计算 a^b % mod long long pow_mod(long long a, long long b, long long mod) { long long ans 1; while (b) { if (b 1) ans ans * a % mod; a a * a % mod; b 1; } return ans; } // 线性素数筛筛出 [1, n] 的所有素数 const int MAXN 1000000; bool is_prime[MAXN 1]; void sieve(int n) { for (int i 2; i n; i) is_prime[i] true; for (int i 2; i * i n; i) { if (is_prime[i]) { for (int j i * i; j n; j i) { is_prime[j] false; } } } }gcd用递归层数最多O(log min(a,b))不用怕爆栈。pow_mod里的b 1是位运算判断二进制最后一位是不是1相当于b % 2 1写熟了这一类位运算代码会短很多。素数筛要注意j从i*i开始避免重复标记i*i可能会溢出int所以我习惯用1LL * i * i做判断这在杭电多年题目里确实遇到过边界坑。3.3 时间复杂度的估算1秒能跑多少杭电的Time Limit多数是1000MS也就是1秒。1秒在评测机上大概能跑多少这个数值没有精确答案但是有个经验范围10^8次简单整数操作大约是极限超过这个量级大概率TLE10^7次运算很稳10^6次随便跑。所以拿到一道题先看数据范围——这是所有刷题技巧里最重要的一步。数据范围是n 10^5你的算法要是O(n^2)那就是10^10次运算直接超时不用交了。记住这个估算O(n^2)的算法能处理约10^4到10^5的数据量O(n log n)可以处理10^6甚至10^7O(n)阈值大约在10^7到10^8O(2^n)只能处理n20左右。看到题目先算复杂度再动手这能省掉你大量的WA和TLE调试时间。很多人在杭电刷到300题左右会卡住不是不会做而是没把复杂度和数据范围关联起来用了错误级别的算法交上去TLE一排。4. 刷题路线规划从1000题到2000题怎么刷4.1 入门段位HDU 1000~1099的数学与模拟杭电OJ的题号从1000开始不是按难度排的但前100多题整体偏基础适合热身。这一段的题目构成大约是20%的AB级别输入输出题30%的简单数学题素数、GCD、阶乘30%的字符串处理和模拟剩下的10%会突然出现一道需要点思维的题比如递推或贪心。我建议新手在这个段位不要跳题按顺序刷。原因很简单你能从这里看到杭电出题的风格——它喜欢把算法藏在看起来很麻烦的现实场景里。比如“一只小蜜蜂...”那种题名字看起来是模拟实际是斐波那契数列递推。你在前100题里见过这种包装方式后面遇到“一只青蛙”才会条件反射去想递推而不是真的去模拟青蛙跳。4.2 进阶段位DP、图论、字符串三座山过了入门段你会发现杭电的高频考点非常固定动态规划、图论算法、字符串处理。DP这块杭电的题能从最简单的数塔HDU 2084一路做到状态压缩DP中间隔了几十道递推变形。图论则是从并查集开始到最短路、最小生成树、网络流。字符串是从KMP到AC自动机难度跨度很大。刷到这一段我自己的策略是“专题刷”而不是按题号刷。比如这个星期只做DP把所有经典DP模型过一遍背包九讲、LIS、LCS、区间DP、数位DP。杭电的搜索功能支持按关键词过滤你可以搜“dp”或者去讨论区看别人整理的题单。专题刷的好处是同一个算法连做十道题后你对它的边界条件会形成肌肉记忆比如背包问题里for j : v..0和for j : 0..v的区别刷几道自然就忘不掉了。4.3 怎么筛选“水题”和“神题”杭电OJ有些题是出名的“坑题”看起来简单数据里全是边界。如果你想用这个题库备战正式比赛那就必须有筛选能力。看Submission和Accepted的比例是个好办法一道题提交1000次只有100个AC说明要么是难要么是坑。我一般刷题前会先看这个比例按AC比例从高到低刷把submit/ac比值当成难度标签。有一个反直觉的经验AC比例特别高的题不一定简单可能是提交人数基数大AC比例特别低的题也不一定难可能只是题意描述有歧义。所以更可靠的办法是看“讨论区”和“题解”。杭电的讨论区里经常有人直接讨论测试数据能帮你少走很多弯路。如果看到一道题的题解区清一色说“这道题数据有问题”那就跳过如果有人说“用了long long才过”那你就要警惕int溢出。5. 杭电OJ刷题避坑提交PE、超时与WA的常见翻车现场5.1 永远记不住的输出格式Presentation Error现象代码逻辑和样例输出完全一样本地运行结果跟题目样例一字不差提交却返回PE而不是AC。看判题详情提示你“output format error”。原因PE的本质是你的输出和标准答案只在空白字符上有差异。最常见的两种多输出了一个空格或者少输出了一个空行。很多题要求输出Case #x: answer中间的空格数量不能多不能少还有些题要求每组输出之间有一个空行但最后一组之后不能有空行。解决把你的输出重定向到文件和题目的样例输出文件逐字节对比。在本地用diff out.txt ans.txt看差异。如果是空行问题就把打印空行的逻辑改成“除第一组外每组之前打印一个空行”而不是“每组之后打印一个空行”。这个坑我刷杭电的时候踩过不下五次每次都是PE后来养成了习惯所有多组输出的题一律用“第一组不打空行后续打”的写法。5.2 memset按字节初始化int数组翻车现场现象用了memset(dist, 0x3f, sizeof(dist))初始化一个int数组然后判断if (dist[i] INF)跑出来的结果不对有的最短路径没有更新。原因memset是按字节填充的0x3f填充到每个字节上所以一个int4字节存的是0x3f3f3f3f不是0x3f。而且0x3f3f3f3f作为无穷大是可以用的关键是你的INF宏要定义成和这个值一致。如果你定义#define INF 0x3f3f3f3f然后memset(dist, INF, sizeof(dist))由于INF是int类型memset只取最低位字节0x3f结果还是正确的。怕就怕你memset用0x3f判断却用 INF这里INF可能是0x3f3f3f3f也可能你定义错了就会出现“memset后的值不等于INF”这种诡异情况。解决统一写法const int INF 0x3f3f3f3f;然后memset(dist, 0x3f, sizeof(dist));。注意memset往bool数组和char数组填充没问题但填充int数组时要想清楚。还有一个更安全的替代方案用std::fillfill(dist, dist n, INF);虽然慢一点但语义清晰不容易错。5.3 scanf与cin的同步关闭超时的隐形元凶现象同一套算法别人AC你交上去TLE。代码里用的是cin n;数据量一大就超时。原因C的cin为了兼容C的scanf默认会做同步缓冲导致读入速度变慢好几倍。杭电很多题的数据规模在10^5以上输入量大时差距就暴露了。解决在main开头加两行ios::sync_with_stdio(false); cin.tie(0);第一行关闭与stdio的同步第二行把cin和cout解绑。加了之后cin就很快了能够逼近scanf。副作用是你不能混用cin和scanf、cout和printf因为同步关闭后它们的缓冲区各自独立会乱序。嫌麻烦的话干脆全用scanf和printf我一直是这么干的省心。5.4 数组开小Runtime Error的经典原因现象本地运行一切正常提交后返回RE。看错误信息没有除零没有野指针最后发现是数组越界。原因题目说n 1000你开了int a[1000]但测试数据可能刚好有n 1000你访问了a[1000]越界了一个位置。很多RE都是这种差一错误。还有一种情况是开二维数组int dp[100][100]但实际数据是m 1000直接爆内存。解决开数组时多看几遍数据范围习惯性多开5到10个位置。int a[1005]比a[1000]安全int dp[1005][1005]也比dp[1000][1000]稳妥。内存一般情况下够用1KB的浪费换来的是一晚上不用查越界。对于不确定的边界可以在本地跑一下极限数据用最大的n构造一组输入看会不会崩。这种事前验证比提交10次试错要高效得多。5.5 提交代码别带文件读写本地跑通提交WA现象本地用freopen(input.txt, r, stdin)调试跑出正确答案提交到杭电OJ直接WA连编译都过了但结果全错。原因评测机只认标准输入输出freopen会在评测系统上没有input.txt这个文件读入直接失败程序按默认值跑输出自然全错。这是新手最容易犯的错因为他们用IDE调试时习惯重定向到文件。解决提交前检查代码里所有freopen和fopen全部注释掉。我一般会在本地保留一个带freopen的调试版本在提交前用文本替换把这几行删掉。或者更稳妥的做法是把文件重定向包在预处理宏里#ifdef LOCAL freopen(input.txt, r, stdin); #endif本地加-DLOCAL编译提交时不加这个宏文件读写代码就不参与编译。这个技巧能省下很多次“交了WA才发现忘了注释”的翻车现场。除了文件读写还有一类提交后翻车的代码是用了system(pause)这类卡在等待按键的代码一定要在提交前干掉。6. 把杭电OJ刷出价值三件提升效率的事6.1 自己搭一个校赛训练排期杭电OJ有Virtual Judge功能可以自己挑选题目组合成一场模拟赛。用这个功能做每周一次的限时训练效果比漫无目的刷题好很多。具体做法是每周从题库里挑4到6道题难度递增模拟正式比赛的题目分布限时2到3小时结束后统一看成绩。这能练习你的时间分配——哪些题先放弃、哪些题必须拿分。很多人在正式比赛里翻车不是不会写而是第一道难题卡了2小时简单题没时间做。用虚拟比赛多练几次时间感就出来了。6.2 赛后补题比刷新题重要每次做完模拟赛哪怕AC了所有题也值得赛后复盘。我在杭电的经历是一道题AC了但用的是复杂度过高的解法看别人题解发现有更优做法这种认知升级只有在赛后补题里才会发生。补题的正确步骤是先看自己AC的代码能不能优化再看没AC的题的标准题解最后不看题解自己重新写一遍。一件反直觉的事是刷题数量多不如补题数量多。一周认真补3道题好过刷20道水题。因为补题是在补自己的认知漏洞刷水题只是在增加熟悉度。复盘时我会把自己写过的题的代码打开看有没有可以改成模板的地方比如把求最大公因数的代码抽成函数下次遇到直接调用。6.3 学会利用Discuss但不要迷信题解杭电的Discuss区有很多人发测试数据也有不少人发错误结论。看题解要注意一条原则先自己想想不出来再看。而且看题解时不要只盯着代码要看思路推导过程。我见过很多刷题到后半段的人每次遇到题就搜题解搜到了就交交了就过过了就忘刷了2000道仍然没有进步。宁可一道题想三小时然后放弃看题解也不要遇到困难就去找现成答案——这是杭电OJ真正能给你的东西也是刷题这件事唯一的长期价值。对于一个诚心想在算法上往前走的人我希望帮到你。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门