HydroOJ 从入门到入土(7)Hydro自带数据生成器使用说明(>=4.10.1)(24.06.13更新)
Hydro更新了一个新功能, 可以直接用自带的数据生成器, 在线生成数据, 简单记录一下使用方法
1. 文件准备
- gen.py / gen.cpp (数据生成器, 后附模版)
- std.cpp (标准程序, 后附模版)
文件名随意, 其他的类型只要系统支持能执行的都行, 可以自己写, 注意是标准输出, 不需要文件读写, 系统会自动处理.
2. 使用步骤
- 将以上两个文件上传到测试数据里
- 在
生成测试数据(Beta)
的两个栏里, 分别填上gen.py
和std.cpp
- 点击生成, 此时会弹出一个界面,
running
并且generating
数据点. - 成功生成完成之后, 检查一下自己的测试数据, 应该已经有若干测试数据了.
3. 注意事项
- 生成器只需要生成输入文件, 标准输出, 比如 print
- 可以通过读取文件运行的命令行参数 sys argv 来得到当前在生成第几个点, 这样可以根据题目要求控制对应数据规模
- 目前默认生成 10 个点, 通过上边第 2 点的数量控制, 可以使数据点生成少于 10 个. 如果需要多于 10 个, 需要修改源码(在这里)
- 默认不支持 cyaron, 得自己处理 nix 下的 python 环境, 参考HydroOJ 从入门到入土(10) 配置 nix 支配下的 Python 环境.
- 新增了一个 cpp 的模版(2024.06.13),生成大量随机数据时用 cpp 会快点,实测 5mb 级的数据大概比 py 快 5 倍左右(30ms vs 150ms),越大快的越多。
4. 单点数据限制 4mb(2024.06.13)
目前数据生成器的默认单点数据限制是 4mb,控制面板中的 stdio_size
设置对此无效(除非小于 4mb)。
具体原因:源码地址
另根据 undefined 在群内的回复(2024.06.13):“大数据还是本地跑好了传,而不是跑一遍 看一下 再跑一遍,那样流量消耗太大了”。如果 oj 配置的是外部独立评测机,反复生成数据会在评测机和服务器上来回传,大幅增加流量消耗。
如果评测机和 oj 是在同一个服务器上,则不会产生额外流量消耗。
手动修改方法:
vi +80 /usr/local/share/.config/yarn/global/node_modules/@hydrooj/hydrojudge/src/sandbox.ts
// 将这行:
const stdioSize = params.cacheStdoutAndStderr ? stdioLimit : 4;
// 改为:
const stdioSize = params.cacheStdoutAndStderr ? stdioLimit : 15;
然后pm2 restart hydro-sandbox hydrooj
生效。
注意不要改太大,因为自测
也是这个限制,改大了可能在自测
的时候会造成网页卡顿或者消耗更多流量。
5. 文件模版
gen.py
# from cyaron import *
import random
import sys
_n = list(map(int, [0, 1e2, 5e2, 1e3, 1e4, 1e4])) # 默认生成 10 个点, 数据点不够也没事, 不会生成无效数据
_m = list(map(int, [0, 20, 40, 60, 80, 100]))
k = int(sys.argv[1]) # 读入当前正在生成的数据点编号, 从 1 开始
nums = range(_n[k])
n = random.randint(5, _m[k])
ls = random.sample(nums, n)
for i in range(n):
ls[i] *= random.choice([-1, 1])
print(n)
print(*ls)
gen.cpp
#include <bits/stdc++.h>
using namespace std;
using ull = unsigned long long;
int main(int argc,char *argv[]){
int i = stoi(argv[1]);
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> t(1, 50);
uniform_int_distribution<ull> n(11, ull(1e18));
ios::sync_with_stdio(0);
switch (i) {
case 1 ... 2:
break;
case 3 ... 6:
t.param(decltype(t)::param_type (1, ull(5e5)));
n.param(decltype(n)::param_type (11, ull(1e6)));
break;
case 7 ... 10:
t.param(decltype(t)::param_type (ull(1e4), ull(5e5)));
n.param(decltype(n)::param_type (ull(1e10), ull(1e18)));
break;
}
int tt=t(gen);
printf("%d\n", tt);
for (int i = 0; i < tt; i++){
printf("%lld\n", n(gen));
}
return 0;
}
std.cpp
#include <bits/stdc++.h>
using namespace std;
int a[110], n;
bool cmp(int a, int b){ return abs(a) > abs(b); }
int main(){
cin >> n;
for (int i = 0; i < n; ++i)
cin >> a[i];
sort(a, a+n, cmp);
for (int i = 0; i < n; ++i)
cout << a[i] << ' ';
return 0;
}