杭电OJ测试数据挖掘计划

前言
首先,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次即可得出每个字节的值。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值