1 条题解
-
0
你好!作为一名 OI 教练,我非常理解你需要一套高质量、覆盖全面的测试数据来验证学生的代码。
为了方便你直接使用,我编写了一个 “一键生成工厂” 的 C++ 程序。这个程序运行后,会在当前目录下自动生成
1.in~10.in以及对应的标准答案1.out~10.out。核心设计思路
- 覆盖度:
- 小数据 (1-3):方便手动计算验证,包含正数、负数混合。
- 边界情况 (4-6):
- 全零/倍数序列:测试
ans是否会爆int(答案最大为 ,必须用long long)。 - 极小 K:,测试奇偶性同余。
- 极大 K:。
- 全零/倍数序列:测试
- 大数据 (7-10):,全随机,正负混合,测试时间复杂度 是否达标。
- 安全性:使用了 C++11 的
mt19937随机数生成器,比rand()质量更高且分布更均匀。 - 自动化:生成输入文件后,立即调用内置的标准解答函数生成输出文件,确保数据和答案绝对匹配。
C++ 数据生成器代码 (Generator + Solver)
请将以下代码保存为
gen_data.cpp,编译运行即可。/** * 题目: 序列整除 (Subarray Divisibility) 数据生成器 * 功能: 自动生成 1.in ~ 10.in 及对应的 1.out ~ 10.out * 作者: OI 教练 * * 包含两个部分: * 1. Generator: 根据预设策略生成测试数据 * 2. Solver: 读取生成的 .in 文件,算出标准答案写入 .out 文件 */ #include <bits/stdc++.h> using namespace std; // ================= 标准解答部分 (Solver) ================= // 对应之前教案中的标准解法,用于生成 .out 文件 namespace Solver { const int MAXK = 10005; int cnt[MAXK]; void solve(string intput_file, string output_file) { ifstream fin(intput_file); ofstream fout(output_file); if (!fin.is_open() || !fout.is_open()) { cerr << "Error opening files: " << intput_file << endl; return; } int n, k; fin >> n >> k; // 初始化 memset(cnt, 0, sizeof(cnt)); cnt[0] = 1; // 0 是初始前缀和 long long ans = 0; int current_sum = 0; for (int i = 0; i < n; ++i) { int val; fin >> val; current_sum += val; // 核心公式:处理负数取模 int remainder = (current_sum % k + k) % k; ans += cnt[remainder]; cnt[remainder]++; } fout << ans << endl; fin.close(); fout.close(); cout << "Generated: " << output_file << " (Ans: " << ans << ")" << endl; } } // ================= 数据生成部分 (Generator) ================= namespace Generator { mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); // 生成范围 [min, max] 的随机整数 int random_int(int min_val, int max_val) { uniform_int_distribution<int> dist(min_val, max_val); return dist(rng); } // 生成数据的主函数 // id: 测试点编号 // n: 序列长度 // k: 除数 // min_val, max_val: 数组元素的值域 // type: 特殊构造类型 (0:随机, 1:全是K的倍数, 2:含大量0) void make_data(int id, int n, int k, int min_val, int max_val, int type) { string in_file = to_string(id) + ".in"; string out_file = to_string(id) + ".out"; ofstream fout(in_file); fout << n << " " << k << "\n"; for (int i = 0; i < n; ++i) { int val; if (type == 0) { // 普通随机 val = random_int(min_val, max_val); } else if (type == 1) { // 特殊构造:全是 K 的倍数 // 这种情况下任意子段和都能整除 K,答案应为 N*(N+1)/2 // 用于测试答案是否用了 long long int mul = random_int(min_val / k, max_val / k); val = mul * k; } else if (type == 2) { // 特殊构造:大量 0 (80% 概率为0) if (random_int(1, 100) <= 80) val = 0; else val = random_int(min_val, max_val); } fout << val << (i == n - 1 ? "" : " "); } fout << "\n"; fout.close(); // 生成完输入后,立即调用 Solver 生成输出 Solver::solve(in_file, out_file); } } int main() { // 加速 ios::sync_with_stdio(false); cout << "--- Starting Data Generation ---" << endl; // 测试点 1-3: 小规模数据,方便调试,包含负数 Generator::make_data(1, 10, 5, 0, 10, 0); // 纯正数小数据 Generator::make_data(2, 50, 7, -10, 10, 0); // 混合正负小数据 Generator::make_data(3, 100, 13, -100, 100, 0); // 稍大的小数据 // 测试点 4-6: 边界与特殊情况 // Point 4: 大量 0 (0 被任何数整除,测试 cnt[0] 处理) Generator::make_data(4, 1000, 50, -100, 100, 2); // Point 5: 全是 K 的倍数 (压力测试 long long 溢出) // N=1000, Ans ≈ 5*10^5,稍微大一点 Generator::make_data(5, 5000, 10, -1000, 1000, 1); // Point 6: K 极小 (K=2),测试奇偶性 Generator::make_data(6, 10000, 2, -10000, 10000, 0); // 测试点 7-10: 大规模随机数据 (10^5 级别) // Point 7: N 大,K 中等,正数 Generator::make_data(7, 100000, 233, 1, 10000, 0); // Point 8: N 大,K 大,负数多 Generator::make_data(8, 100000, 9999, -10000, -1, 0); // Point 9: N 最大,K 中等,完全随机 (-10000 ~ 10000) Generator::make_data(9, 100000, 5000, -10000, 10000, 0); // Point 10: 极限数据 N=10^5, K=10^4 Generator::make_data(10, 100000, 10000, -10000, 10000, 0); cout << "--- All 10 test cases generated successfully! ---" << endl; return 0; }测试点详细设计说明
测试点 数据特征 考察目的 1 10 5 小范围正数 基础逻辑验证,方便手算核对 2 50 7 含少量负数 验证 (sum%k + k)%k的初步正确性3 100 13 较多负数 进一步验证负数同余处理 4 1000 50 大量 0 0 对前缀和无影响,测试逻辑是否被大量相同前缀和卡住 5 5000 10 全为 K 的倍数 答案为最大值 ,必测 long long是否溢出6 10000 2 (奇偶) 只有余数 0 和 1 两个桶,测试桶的高频冲突 7 233 纯正数,大 N 测试无负数情况下的时间复杂度 8 9999 纯负数,大 N 测试全负数前缀和递减情况下的正确性 9 5000 强随机,正负混合 模拟真实竞赛数据的平均分布情况 10 极限数据 题目给定范围的上限测试,验证 1.0s 内通过 使用方法
- 将代码保存为
gen.cpp。 - 编译:
g++ gen.cpp -o gen -O2(推荐开启 O2 优化,虽然生成器通常不需要,但是个好习惯)。 - 运行:
- Windows:
gen.exe - Linux/Mac:
./gen
- Windows:
- 运行结束后,你会发现当前文件夹下多了
1.in~10.in和1.out~10.out共20个文件。 - 将这些文件上传到你的 OJ 后台即可。
这个生成器不仅生成数据,还自带了我们在教案中讨论过的“标准解答”来产生输出,保证了数据的一致性。希望能帮助你顺利完成题目配置!
- 覆盖度:
- 1
信息
- ID
- 19329
- 时间
- 1000ms
- 内存
- 32MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 1
- 已通过
- 1
- 上传者