2 条题解
-
0
这是一个完整的 C++ 数据生成器,用于生成“能量采集器 (Matrix Block Sum)”题目的测试数据。
它包含了一个标准的二维前缀和解法,用于生成正确的
.out文件,并精心设计了 10 个测试点,覆盖了从样例、边界情况(如 矩阵、单行、单列、全图覆盖)到最大规模压力测试的各种场景。数据生成器代码 (generator.cpp)
您可以将以下代码保存为
generator.cpp,编译并运行。它将在当前目录下生成1.in/1.out到10.in/10.out。#include <iostream> #include <fstream> #include <vector> #include <string> #include <random> #include <ctime> #include <algorithm> using namespace std; typedef long long ll; // ========================================== // 1. 标准解法函数 (用于生成 .out 文件) // ========================================== // 输入:N, M, K 和 原始矩阵 // 输出:结果矩阵 vector<vector<ll>> solve(int n, int m, int k, const vector<vector<int>>& mat) { // 1. 计算二维前缀和 // s[i][j] 表示 (1,1) 到 (i,j) 的矩形和 // mat 是 0-based, s 是 1-based 以方便计算 vector<vector<ll>> s(n + 1, vector<ll>(m + 1, 0)); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { // mat[i-1][j-1] 是当前值 s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + mat[i - 1][j - 1]; } } // 2. 计算每个位置的采集结果 vector<vector<ll>> res(n, vector<ll>(m)); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { // 计算边界,利用 max 和 min 防止越界 // 题目要求范围 [i-k, i+k], [j-k, j+k] int r1 = max(1, i - k); int c1 = max(1, j - k); int r2 = min(n, i + k); int c2 = min(m, j + k); // 查询公式:大 - 上 - 左 + 左上 res[i - 1][j - 1] = s[r2][c2] - s[r1 - 1][c2] - s[r2][c1 - 1] + s[r1 - 1][c1 - 1]; } } return res; } // ========================================== // 2. 随机数辅助工具 // ========================================== mt19937 rng(time(nullptr)); // 生成 [min, max] 范围内的随机整数 int random_int(int min, int max) { uniform_int_distribution<int> dist(min, max); return dist(rng); } // ========================================== // 3. 测试点生成逻辑 // ========================================== void generate_test_case(int id) { int N, M, K; int min_val = 1, max_val = 100; // 题目范围 1 <= A[i][j] <= 100 string desc; // 根据 id 设定测试点参数 switch (id) { case 1: // 样例数据 N = 3; M = 3; K = 1; desc = "Sample Case"; break; case 2: // 极小边界 (1x1, K=0) N = 1; M = 1; K = 0; desc = "Smallest 1x1, K=0"; break; case 3: // 极小边界 (1x1, K=1) N = 1; M = 1; K = 1; desc = "Smallest 1x1, K=1 (Full Cover)"; break; case 4: // K=0 测试 (结果应与原矩阵相同) N = 10; M = 10; K = 0; desc = "K=0 Identity Check"; break; case 5: // K 非常大 (全图覆盖) N = 20; M = 20; K = 100; desc = "Large K (Full Matrix Sum)"; break; case 6: // 单行矩阵 (1x1000) N = 1; M = 1000; K = 2; desc = "Row Vector"; break; case 7: // 单列矩阵 (1000x1) N = 1000; M = 1; K = 2; desc = "Column Vector"; break; case 8: // 中等规模随机 N = 100; M = 100; K = 5; desc = "Medium Random"; break; case 9: // 大规模,K=1 (基础压力测试) N = 1000; M = 1000; K = 1; desc = "Large Matrix K=1"; break; case 10: // 最大规模,大 K (最大压力测试) N = 1000; M = 1000; K = 500; desc = "Max Constraints (N=1000, K=500)"; break; default: N = 10; M = 10; K = 1; } // --- 生成矩阵数据 --- vector<vector<int>> matrix(N, vector<int>(M)); if (id == 1) { // 样例固定数据 matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; } else { for (int i = 0; i < N; ++i) { for (int j = 0; j < M; ++j) { matrix[i][j] = random_int(min_val, max_val); } } } // --- 写入 .in 文件 --- string in_filename = to_string(id) + ".in"; ofstream fin(in_filename); fin << N << " " << M << " " << K << "\n"; for (int i = 0; i < N; ++i) { for (int j = 0; j < M; ++j) { fin << matrix[i][j] << (j == M - 1 ? "" : " "); } fin << "\n"; } fin.close(); // --- 计算答案并写入 .out 文件 --- vector<vector<ll>> result = solve(N, M, K, matrix); string out_filename = to_string(id) + ".out"; ofstream fout(out_filename); for (int i = 0; i < N; ++i) { for (int j = 0; j < M; ++j) { fout << result[i][j] << (j == M - 1 ? "" : " "); } fout << "\n"; } fout.close(); cout << "Generated Case " << id << ": " << desc << " (N=" << N << ", M=" << M << ", K=" << K << ")" << endl; } int main() { // 加速 I/O ios::sync_with_stdio(false); for (int i = 1; i <= 10; ++i) { generate_test_case(i); } cout << "All test cases generated successfully!" << endl; return 0; }测试点详细设计说明
- Case 1 (Sample): 题目描述中的样例,用于最基础的正确性验证。
- Case 2 (Smallest K=0): 矩阵,。测试最小边界,结果应等于输入。
- Case 3 (Smallest K=1): 矩阵,。虽然范围覆盖出去了,但物理只能采到这一个点,测试边界截断逻辑。
- Case 4 (K=0 Identity): 。当 时,采集范围就是自身,输出矩阵应与输入矩阵完全一致。
- Case 5 (Full Cover): 。采集范围覆盖全图,每个点的结果都应该是整个矩阵的总和。测试
max/min边界处理是否正确。 - Case 6 (Row Vector): 。退化为一维数组,测试 时的行边界处理。
- Case 7 (Col Vector): 。测试 时的列边界处理。
- Case 8 (Medium Random): 。常规随机数据,检验一般情况下的正确性。
- Case 9 (Large Matrix K=1): 。大规模数据,主要测试前缀和构建和查询的效率( vs 的差异)。
- Case 10 (Stress Test): 。最大规模压力测试,同时因为 很大且元素最大 100,测试
long long是否能防止数值溢出(最大和约 ,int其实够用,但用long long更保险)。
如何使用
- 保存:将代码保存为
generator.cpp。 - 编译:
g++ generator.cpp -o generator -O2 - 运行:
./generator - 结果:当前文件夹下会生成
1.in,1.out...10.in,10.out。可以直接上传到 OJ 后台。
-
0
/** * 题目:能量采集器 (Matrix Block Sum) * 知识点:二维前缀和 (2D Prefix Sum) * 时间复杂度:O(N * M) * 空间复杂度:O(N * M) */ #include <iostream> #include <vector> #include <algorithm> // 用于 max, min 函数 using namespace std; // 使用 long long,养成好习惯 typedef long long ll; const int MAXN = 1005; ll s[MAXN][MAXN]; // 二维前缀和数组 int mat[MAXN][MAXN]; // 原数组 int main() { // 1. IO 优化 ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, k; if (!(cin >> n >> m >> k)) return 0; // 2. 读入数据并预处理二维前缀和 // s[i][j] 表示 (1,1) 到 (i,j) 的矩形和 for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { cin >> mat[i][j]; // 构造公式:上 + 左 - 左上 + 自己 s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + mat[i][j]; } } // 3. 对每个点进行查询 for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { // 计算边界,利用 max 和 min 防止越界 // 题目要求范围 [i-k, i+k], [j-k, j+k] int r1 = max(1, i - k); int c1 = max(1, j - k); int r2 = min(n, i + k); int c2 = min(m, j + k); // 查询公式:大 - 上 - 左 + 左上 ll ans = s[r2][c2] - s[r1 - 1][c2] - s[r2][c1 - 1] + s[r1 - 1][c1 - 1]; // 输出格式控制 cout << ans << (j == m ? "" : " "); } cout << "\n"; } return 0; }
- 1
信息
- ID
- 19322
- 时间
- 1000ms
- 内存
- 32MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 3
- 已通过
- 3
- 上传者