1 条题解
-
0
这是一个符合OI竞赛出题标准的数据生成器(Data Generator)。它会自动生成
1.in~10.in以及对应的标准答案1.out~10.out。设计思路
为了保证数据的合法性(不爆
int)和覆盖性(全面测试),数据生成策略如下:-
数据规模分级:
- 1-3 点:小规模数据,方便手动调试观察。
- 4-6 点:中等规模, 逐渐增大,包含纯 1/-1 的情况。
- 7-10 点:大规模数据(),重点测试性能和边界。
-
数值构造策略(关键):
- 题目限制了任意前缀/后缀积都在32位整数内。这意味着数组中绝对值大于1的数非常少(因为 ,即使全是 2,最多也只能有 30 个左右)。
- 因此,大数据生成逻辑必须是:生成少量的大数(或0),其余位置全部用
1或-1填充,最后打乱顺序。 - 0 的处理:专门构造含 1 个 0、2 个 0 和无 0 的情况。
-
文件生成:使用 C++ 的
fstream进行文件读写。
C++ 数据生成器代码
请将以下代码保存为
gen.cpp,编译运行即可在当前目录下生成所有测试数据。#include <bits/stdc++.h> using namespace std; // ========================================== // 配置区域 // ========================================== const int TEST_CASE_COUNT = 10; // 测试点数量 const int MAX_VAL_LIMIT = 30; // 题目要求的数值范围 [-30, 30] const int INF_INT = 2000000000; // 安全的 int 阈值 // ========================================== // 随机数生成器 (基于 mt19937) // ========================================== mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); int random_int(int l, int r) { uniform_int_distribution<int> dist(l, r); return dist(rng); } // ========================================== // 标准解答算法 (Solver) // 用于生成 .out 文件 // ========================================== vector<int> solve(int n, const vector<int>& nums) { vector<int> ans(n); // 1. 计算前缀积 ans[0] = 1; for (int i = 1; i < n; ++i) { ans[i] = ans[i - 1] * nums[i - 1]; } // 2. 计算后缀积并合并 int R = 1; for (int i = n - 1; i >= 0; --i) { ans[i] = ans[i] * R; R = R * nums[i]; } return ans; } // ========================================== // 数据构造逻辑 // ========================================== // 生成一组符合题目要求的数据 // n: 数组长度 // zero_count: 0 的个数 (-1 表示随机 0-2 个) // large_nums_allowed: 是否允许生成绝对值 > 1 的数 vector<int> generate_case(int n, int zero_count = -1, bool large_nums_allowed = true) { vector<int> a; // 1. 确定 0 的个数 if (zero_count == -1) { int type = random_int(0, 10); if (type < 7) zero_count = 0; // 70% 概率无 0 else if (type < 9) zero_count = 1; // 20% 概率 1 个 0 else zero_count = 2; // 10% 概率 2 个 0 } // 添加 0 for (int i = 0; i < zero_count && a.size() < n; ++i) { a.push_back(0); } // 2. 添加绝对值 > 1 的数 (控制总乘积不溢出) long long current_prod = 1; if (large_nums_allowed && a.size() < n) { // 尝试添加一些大数,直到乘积快溢出 int attempts = 0; while (a.size() < n && attempts < 1000) { attempts++; // 随机选一个 [-30, 30] 之间非 0 非 1 的数 int val = random_int(-MAX_VAL_LIMIT, MAX_VAL_LIMIT); if (val == 0 || val == 1 || val == -1) continue; // 检查乘积是否溢出 (留一点余量) if (abs(current_prod * val) < INF_INT) { current_prod *= val; a.push_back(val); } else { // 如果已经很大了,就停止添加大数 break; } } } // 3. 剩余位置填充 1 或 -1 while (a.size() < n) { a.push_back(random_int(0, 1) ? 1 : -1); } // 4. 打乱顺序 shuffle(a.begin(), a.end(), rng); return a; } // ========================================== // 主程序:生成 1~10 测试点 // ========================================== int main() { printf("Starting data generation...\n"); for (int id = 1; id <= TEST_CASE_COUNT; ++id) { int n; vector<int> nums; // --- 针对不同测试点定制数据 --- if (id == 1) { // 测试点 1: 极小数据 (n=5),随机 n = 5; nums = generate_case(n, 0, true); } else if (id == 2) { // 测试点 2: 小数据 (n=10),包含 1 个 0 n = 10; nums = generate_case(n, 1, true); } else if (id == 3) { // 测试点 3: 小数据 (n=20),包含 2 个 0 n = 20; nums = generate_case(n, 2, true); } else if (id == 4) { // 测试点 4: 中数据 (n=100),全是 1 (单位元测试) n = 100; nums.assign(n, 1); } else if (id == 5) { // 测试点 5: 中数据 (n=1000),全是 1 和 -1 (符号测试) n = 1000; nums = generate_case(n, 0, false); // 不允许大数,只允许 1/-1 } else if (id == 6) { // 测试点 6: 大数据 (n=10^5),稀疏大数,无 0 n = 100000; nums = generate_case(n, 0, true); } else if (id == 7) { // 测试点 7: 大数据 (n=10^5),稀疏大数,含 1 个 0 n = 100000; nums = generate_case(n, 1, true); } else if (id == 8) { // 测试点 8: 大数据 (n=10^5),含多个 0 (测试全0输出) n = 100000; nums = generate_case(n, 5, true); // 5个0 } else if (id == 9) { // 测试点 9: 大数据,乘积接近 INT_MAX (正边界) // 构造逻辑:尽可能乘到接近 20亿,然后填 1 n = 100000; nums.clear(); long long p = 1; while(nums.size() < n) { int v = random_int(2, 5); // 选用较小的正数慢慢乘 if (p * v < 2000000000) { p *= v; nums.push_back(v); } else { break; } } while(nums.size() < n) nums.push_back(1); shuffle(nums.begin(), nums.end(), rng); } else { // 测试点 10: 大数据,包含边界值 -30 和 30 n = 100000; nums.clear(); nums.push_back(30); nums.push_back(-30); while(nums.size() < n) nums.push_back(random_int(0, 1) ? 1 : -1); shuffle(nums.begin(), nums.end(), rng); } // --- 生成 .in 文件 --- string in_file_name = to_string(id) + ".in"; ofstream fin(in_file_name); fin << n << "\n"; for (int i = 0; i < n; ++i) { fin << nums[i] << (i == n - 1 ? "" : " "); } fin << "\n"; fin.close(); // --- 生成 .out 文件 --- string out_file_name = to_string(id) + ".out"; ofstream fout(out_file_name); // 调用标准解答 vector<int> result = solve(n, nums); for (int i = 0; i < n; ++i) { fout << result[i] << (i == n - 1 ? "" : " "); } fout << "\n"; fout.close(); printf("Generated Test Case %d: N=%d\n", id, n); } printf("All data generated successfully.\n"); return 0; }数据测试点详细说明
测试点 数据特征 考察目的 1 5 随机小整数,无 0 基础逻辑验证,方便肉眼 debug。 2 10 包含 1 个 0 考察是否正确处理除 0 情况(结果应只有那个 0 对应的位置非 0)。 3 20 包含 2 个 0 考察多 0 情况(结果应全为 0)。 4 100 全是 1 考察对单位元的处理,避免过度计算。 5 1000 全是 1 或 -1 考察符号处理能力,无数值溢出风险。 6 稀疏大数,无 0 大数据性能测试。大部分是 1,只有少量大数,乘积逼近 INT_MAX。 7 稀疏大数,含 1 个 0 大数据下的单 0 边界处理。 8 含 5 个 0 大数据下的多 0 处理,验证算法是否做了无效计算(虽然 无论多少0都一样)。 9 乘积接近 正无穷 () 边界测试,确保 int不溢出。10 包含 -30 和 30 边界值测试,确保题目给定的值域范围被覆盖,且负数乘积正确。 使用方法
- 将代码保存为
gen.cpp。 - 使用 g++ 编译:
g++ gen.cpp -o gen -O2。 - 运行:
./gen(Windows 下是gen.exe)。 - 程序运行结束后,你的文件夹下会出现
1.in~10.in和1.out~10.out。 - 将这些文件打包 zip 即可上传至 OJ 后台。
-
- 1
信息
- ID
- 19330
- 时间
- 1000ms
- 内存
- 32MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 1
- 已通过
- 1
- 上传者