跳到主要内容

传统题数据格式要求

格式要求

在传统题(即可以一次性从标准输入中读入、一次性输出到标准输出,不存在交互过程)中,每个测试点的数据包含恰好一个输入文件,并且洛谷还要求恰好一个输出文件(即使可以为空)。

除开个别可能的特殊题目外,对一般的传统题的输入输出数据格式有要求,此要求与 NOIP、NOI、IOI、ICPC 等主流赛事应当保持大致同步:

  • 未在题面中特殊说明并强调时,输入文件必须仅包含 ASCII 中的可见字符空格、以及换行符,具体地:

    可见字符包含:

    • 数字,即 0123456789,对应 ASCII 编码中的 485748 \sim 57
    • 大写英文字母,即 ABCDEFGHIJKLMNOPQRSTUVWXYZ,对应 ASCII 编码中的 659065 \sim 90
    • 小写英文字母,即 abcdefghijklmnopqrstuvwxyz,对应 ASCII 编码中的 9712297 \sim 122
    • 字符 !"#¥%&'()*+,-./(其中 应为美元符),对应 ASCII 编码中的 334733 \sim 47
    • 字符 :;<=>?@,对应 ASCII 编码中的 586458 \sim 64
    • 字符 [\]^_`,对应 ASCII 编码中的 919691 \sim 96
    • 字符 {|}~,对应 ASCII 编码中的 123126123 \sim 126
    • 其他字符均不为可见字符。
    • 所有可见字符占据 ASCII 编码中的 3312633 \sim 126
      可以使用 C++ 中的标准库函数 int std::isgraph(int) 判断是否为可见字符。

    空格换行符的 ASCII 编码分别为 32321010
    换行符在 C++、Python 等常见语言中的字符或字符串中可以使用 \n 进行转义。

    换句话说,如果输入文件中需要出现这些字符以外的 ASCII 字符、甚至非 ASCII 字符,应询问审核员意见并在最终题面中特殊说明并强调

    一般来说,传统题的输入文件只会出现数字、大写英文字母、小写英文字母、输入负数或浮点数时需要的符号(+-.)、以及空格和换行符。
    存在一些题目的输入文件中需要出现不在此列的标点符号或数学符号等特殊字符,也应在题面中显眼位置指出,以免选手遗漏。

    即使文件中仅存在满足上述要求的字符,也需保证字符编码与 ASCII 兼容。例如,不能使用 UTF-32 或 UTF-16 进行编码。

  • 未在题面中特殊说明时,需要确保输入文件中不存在以下情况(假设文件中仅包含上文允许的字符):

    • 空文件,或仅包含空格或换行符。
    • 空行。形式化地说:文件以换行符开始或存在连续两个换行符。
    • 存在行首空格或行末空格。形式化地说:
      文件以空格开始或存在空格与换行符相邻(连续的两个字符按顺序分别为空格和换行符,或换行符和空格)的情况。
    • 连续的多个空格。
    • 文件以换行符作为最后一个字符。
      注意这一条的意思是输入文件需要以换行符结束。

    事实上,存在一些常见的输入格式违背上述要求的可能性,例如常有输入文件以空行分隔的情况。但除非为了特殊的显示效果,不应该违背上述要求。
    不影响显示效果的前提下应尽可能遵守上述要求。换句话说,以下要求一般比其他要求更应该遵守,除非是为了特殊的字符串处理需要:

    • 不存在行末空格,空白行内不应有空格。
    • 不存在文末超过两个换行符。
    • 以换行符作为最后一个字符。

    而这些要求也是造数据时的常见问题。例如,造数据中向输入文件输出时,应当避免:

    • 输出数组或矩阵时在最后一个元素后仍输出空格。
    • 漏掉文末的换行符。
    • 重复输出文末的换行符。

    如果确实有违背上述要求的需求,也应询问审核员意见并在最终题面中特殊说明。
    例如:如果输入文件中会出现空行,或会出现连续的多个空格,或行首空格,应在题面中特殊说明。

  • 类似洛谷在 Special Judge 中提供了 Testlib 的使用,在此也指出在造数据时可以使用 Testlib 中的 Validator 功能对输入文件进行格式上的检查。

  • 对于题目要求的选手的输出格式,无特殊情况时也应遵守类似规定。

  • 洛谷要求数据中对于每个输入文件提供对应的输出文件,当没有设置 Special Judge 时将会使用忽略行末空格和文末换行的全文比较,此时输出文件也应遵守类似规定。如果使用了 Special Judge,可以根据需要自行设置输出文件的内容,只要不影响给出正确的评测结果即可。

对于提交答案题、交互题等题目类型,上述要求可能不适用,但相通之处的标准应统一,例如在题面中对非常见字符进行说明等。

特别地,在 Windows 或其他非 Unix 系统下造数据后,把文件传输到 Linux 下后,可能出现换行符编码不正确的情况。具体地:

  • 造数据的时候请注意换行符使用 Unix 格式(即 \n)而不是 Windows 格式(即 \r\n),如果是在 Windows 系统下造的数据就有可能出现这个问题,如果使用的是 Windows 系统,可以使用系统自带的记事本(Notepad)打开文件然后看一下右下角显示的是 CRLF 还是 LF,如果是后者就没问题(当然,旧版 Mac 格式(即 \r)也是不行的)。
    在 Windows 下造数据时避免造出 \r\n 格式换行符的方法可以查看附录。

附录:Windows 环境下造数据注意事项

洛谷评测机是 Linux 环境,在一些特定题目中,特别是字符串题,如果换行符格式不正确,而用户使用了 getline(C++ 中)等函数进行读入,就会出现输入错误的情况。这些情况在历次月赛中造成了一定的影响,所以还是需要注意一下。

如果你的数据生成器是使用 C++ 写的,并且在代码中显式对输入输出进行重定向(例如使用 fopenfreopenofstream 等等),只需要使用二进制文件格式输出到文件即可。举个例子:

  • 如果使用 C 风格输入输出,只需要在打开输出文件的时候在 const char* mode 参数中传入 "wb" 即可,其后的 b 字符即代表了二进制格式。
  • 如果使用 C++ 风格输入输出,只需要在定义 std::ofstream 对象时在构造函数的第二个参数 std::ios_base::openmode mode 中传入 std::ios::binary 即可。

如果你的数据生成器不是使用 C++ 写的,并且也在代码中显式对输入输出进行重定向,而且你清楚地知道如何在该语言中使用二进制文件输出,那么使用和上述类似的方法即可。

如果你是使用命令行对标准输出进行重定向的,则比较麻烦,如果你的数据生成器是使用 C++ 写的,可以考虑这样的方法:

  • 我们假设运行命令行时的命令是“[generator] < [parameter_file] > [input_file]”,其中 [parameter_file] 表示该数据点的一些参数,[input_file] 表示该数据点的输入文件。
  • 那么我们把命令行命令改成“[generator] [parameter_file] [input_file]”,即取消重定向。
  • 为了能继续正常接收参数和输出到输入文件,其实 C++ 是可以通过 main 函数的参数接收命令行参数的,格式为:int main(int argc, char *argv[]);
  • 其中 argc 为命令行参数个数,argv[0]argv[argc - 1] 就依次存储了这些参数,例如上面的例子“[generator] [parameter_file] [input_file]”中,有:
    • argc = 3
    • argv[0] = [generator]
    • argv[1] = [parameter_file]
    • argv[2] = [input_file]
  • 所以把 main 的参数写上,然后在 main 的开头加上 freopen(argv[1], "r", stdin);freopen(argv[2], "wb", stdout); 即可,这是对于 C 风格 I/O 的处理方法,C++ 风格的处理方法也是类似的。

上面是对输入文件的 \r\n 的处理方式,推荐输出文件的 \r\n 问题也用类似方式处理。

还有最后一个通用的解决方法:按正常方法造好所有数据后,写一个 dos2unix.cpp

#include <cstdio>

const int SIZE = 100000000;
char buf[SIZE];

int main(int, char *argv[]) {
std::FILE *fin = std::fopen(argv[1], "r");
std::size_t cnt = std::fread(buf, sizeof(char), SIZE, fin);
std::fclose(fin);
std::FILE *fout = std::fopen(argv[1], "wb");
std::fwrite(buf, sizeof(char), cnt, fout);
std::fclose(fout);
return 0;
}

编译成 dos2unix.exe 后,在命令行运行命令 dos2unix.exe [filename] 即可把 \r\n 变成 \n

那么也就是造好所有数据后,记下输入输出文件名,批量使用 dos2unix 把它们改好即可。