跳转至

OJ 返回提交不正确

一个不知名老梗

新人求助,降雨量那题,本机AC提交RE

不同的题目可能会有不同的情况,而 OJ 返回的结果也仅仅是一个参考:

  • 有可能你是因为运算出错导致的超时,此时针对 TLE 结果优化程序性能是没有意义的。

下面是一些可能的情况与解决办法。

本地过了样例,但是提交全错

考虑本地与提交的差异:

  • 开启 O2 优化开关:优化会使得未定义行为报错。
  • Linux / Windows 差异:例如 rand() 范围是 \([0, 2 ^ {31})\) 而不是 \([0, 2 ^ {15})\)

尝试带警告编译,有任何 warning 吗?

  • 对于 long long%d,或者对于 int%lld
  • 需要返回值的函数没有返回值;
  • 可以被编译器发现的,明确的空指针访问与越界等;
  • 无符号与有符号的比较,如无符号整型测试 x < 0 永远为假。

本地使用 O2 编译运行,是否程序行为发生了改变?

  • 通常意味着未定义行为与数组越界。
  • 参考 Runtime Error 查错方法。

Wrong Answer: 错误点数很少

考虑 corner case;浮点数考虑存在精度误差的情况。

考虑整形溢出,与数组开小:部分题目因其特性,只有少部分数据能达到上界。

或者,有可能只是因为数据很弱。

Wrong Answer: 大数据出错

考虑越界,溢出等等。

  • 部分数组越界可能会因为内存特性,恰好修改到了有效地址上,导致答案错误。请参考 Runtime Error 查错方法。
  • 在数据比较大时,需要求的答案也可能很大,导致数据溢出。
  • 有的时候甚至会出现非常奇怪的未定义行为,例如 unordered_map: 记一次有趣的 debug

Time Limit Exceeded

会不会是算法复杂度算错了?注意,OJ 在 TLE 时返回的时间可能是被杀死了,实际用时可能更长。

有没有可能什么地方意外地将 \(O(n \log n)\) 实现为 \(O(n ^ 2)\) 了?

  • 特别注意内存拷贝:所有类是默认值传递的,包括 vectorset 等。需要引用传递(类似 Python 的浅拷贝)请使用 & 来传递引用。

有没有可能死循环 / 死递归了?

部分数组越界可能会导致运行超时,参考 Runtime Error 查错方法。

OJ 时间限制解释

题目通常会给出一个时间限制作为程序实现需要达到的目标。现代 CPU 通常是 GHz 级别,这意味着 CPU 每秒运行 \(\sim 10^9\) 个周期。但是,这并不意味着你的代码能完成 \(10^9\) 次运算:理想情况下,你可能能够在一秒内完成 \(10^9\) 次加减法和位运算,但是你的程序里存在大量耗时的跳转、内存访问等。

对于作业题,你可以大致用 \(10^8\) 作为运算操作量级的估计,通常意味着:

  • 对于 \(n \geq 10^8\),考虑亚线性做法。
  • 对于 \(10 ^ 6 << n \leq 10^8\),需要考虑 \(O(n)\) 的算法;
  • 对于 \(10 ^ 4 \leq n \leq 10^6\)\(O(n \log n), O(n \log^ 2 n)\) 或者 \(O(n \sqrt n)\) 的算法可能可以通过;
  • 对于 \(n \leq 10000\)\(O(n ^ 2)\) 的算法可能可以通过;
  • 对于 \(n \leq 500\)\(O(n ^ 3)\) 的算法可能可以通过。

计算算法复杂度时,我们不关心的常数;但实际实现中,常数可能导致超时。不同题目用不同方法实现常数不一样,上述估计标准也可能随着实现有区别。我们尽可能保证,正常实现的代码在给定的时限内不会超时。

Memory Limit Exceeded

检查数组申请:内存是否真的存得下?会不会多打了一个 0

考虑动态申请的内存超限?如 STL 与 new

Runtime Error

检查内存申请与过深递归。

检查访问无效内存:数组越界,double free,使用失效的迭代器,访问 end() 及以后的元素。

检查整数除 0 错误。

使用调试器测试有问题的数据。

检查未定义行为:例如,是否所有需要返回的地方都正确返回了?你可以打开编译警告发现一些这样的错误。

小黄鸭查错法

如果还没有找到错,你可以大声朗读并解释你的代码,来检查可能被忽视的细节。

构造数据与对拍

当你知道答案有错却无法在代码中找到错误时,你可以尝试构造特殊数据来验证程序。你也可以生成随机数据,将你的程序与在小数据上正确的程序对比验证。

详见 构造数据与对拍