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)\) 了?
- 特别注意内存拷贝:所有类是默认值传递的,包括
vector
,set
等。需要引用传递(类似 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 错误。
使用调试器测试有问题的数据。
检查未定义行为:例如,是否所有需要返回的地方都正确返回了?你可以打开编译警告发现一些这样的错误。
小黄鸭查错法
如果还没有找到错,你可以大声朗读并解释你的代码,来检查可能被忽视的细节。