前言
首先,HDUOJ已经出现多年,上面的大部分经典题目已经被被人咀嚼透烂了,也能通过搜索引擎搜索到许多现成的代码。如果有测试数据,那么就能拿自己的程序的输出与前人的程序的输出进行比对,找出问题所在。
然后,对于没有被别人嚼烂的题目,也可以借助测试数据,更好地分析程序问题所在,不至于仅仅过了简单的Sample而过不了测试数据。
显然,最多只需猜测log2(MAXLEN)次即可,就算他是32位整数,也就是31次猜测,必然得出测试数据的长度来。
优化
对于某些题目,如果我们预先知道了输入数据仅仅是ASCII文本,那么很显然可以将猜测范围缩小至0~127的范围。
对于另一些题目,比如输入是整数,整数之间以空白符(空格、回车、Tab)分割,那么显然猜测范围可以进一步缩小为'0'~'9'以及'\n','\t', ' ',一共13种。如此一来最多只需猜测4次即可得出每个字节的值。
首先,HDUOJ已经出现多年,上面的大部分经典题目已经被被人咀嚼透烂了,也能通过搜索引擎搜索到许多现成的代码。如果有测试数据,那么就能拿自己的程序的输出与前人的程序的输出进行比对,找出问题所在。
然后,对于没有被别人嚼烂的题目,也可以借助测试数据,更好地分析程序问题所在,不至于仅仅过了简单的Sample而过不了测试数据。
最后,对于想刷单题排行榜的人,可以尝试冲击0ms、0KB的极限。
一直很疑惑,哪些0ms,0KB的评判结果是怎么出来的。
测试数据的获取方法
在FAQ页面,可以看到候选答案提交之后ONLINE JUDGE的多种反馈结果。
只需选择其中3种我们有把握一定能产生的错误,那么就可以通过二分法,将测试数据的长度以及测试数据的每个字节都找出来。
获取测试数据的长度
设置猜测长度guess,结合读取到的实际长度,比较两者,分别人为地产生3种错误即可折半地逼近正确的实际长度。
其代码如下
#include <cstdio>
#define MAXLEN 0x7fffffff
#define MINLEN 0
char buffer[0x10000];//64KB
int guess = 0;
// RE
void equal(void)
{
int *ptr = NULL;
*ptr = 0;// access violation
double da= 1.0;
double db = 0.0;
double dc = da / db;
int a = 1;
int b = 0;
int c = a / b + 1;
}
// OLE
void less(void)
{
while (true)
{
fwrite(buffer, sizeof(char), sizeof(buffer), stdout);
}
}
// TLE
void greater(void)
{
while (true)
{
}
}
int main(void)
{
int ch;
int count = 0;
while ((ch = getchar()) != EOF)
{
count++;
}
if (count < guess)
{
less();
}
else if (count == guess)
{
equal();
}
else
{
greater();
}
return 0;
}
显然,最多只需猜测log2(MAXLEN)次即可,就算他是32位整数,也就是31次猜测,必然得出测试数据的长度来。
获取测试数据的每个字节
同样是利用二分法来猜测每个字节的值。每个字节只需最多8次猜测即可得出结果。其代码如下:
#include <cstdio>
int guess = 0;
int skip = 0;
// RE
void equal(void)
{
int *ptr = NULL;
*ptr = 0;// access violation
double da= 1.0;
double db = 0.0;
double dc = da / db;
int a = 1;
int b = 0;
int c = a / b + 1;
}
// OLE
void less(void)
{
while (true)
{
fwrite(buffer, sizeof(char), sizeof(buffer), stdout);
}
}
// TLE
void greater(void)
{
while (true)
{
}
}
int main(void)
{
int ch;
int count = 0;
while ((ch = getchar()) != EOF)
{
if (ch < 0)
{
ch = ch + 256;
}
if (count == skip)
{
int guess = guess;
if (ch == guess)
{
equal();
}
else if (ch < guess)
{
less();
}
else
{
greater();
}
}
count++;
}
return 0;
}
优化
对于某些题目,如果我们预先知道了输入数据仅仅是ASCII文本,那么很显然可以将猜测范围缩小至0~127的范围。
对于另一些题目,比如输入是整数,整数之间以空白符(空格、回车、Tab)分割,那么显然猜测范围可以进一步缩小为'0'~'9'以及'\n','\t', ' ',一共13种。如此一来最多只需猜测4次即可得出每个字节的值。