2 条题解

  • 0
    @ 2025-12-13 0:05:42

    这是一个完整的 C++ 数据生成器,用于生成“能量采集器 (Matrix Block Sum)”题目的测试数据。

    它包含了一个标准的二维前缀和解法,用于生成正确的 .out 文件,并精心设计了 10 个测试点,覆盖了从样例、边界情况(如 1×11 \times 1 矩阵、单行、单列、全图覆盖)到最大规模压力测试的各种场景。

    数据生成器代码 (generator.cpp)

    您可以将以下代码保存为 generator.cpp,编译并运行。它将在当前目录下生成 1.in/1.out10.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;
    }
    

    测试点详细设计说明

    1. Case 1 (Sample): 题目描述中的样例,用于最基础的正确性验证。
    2. Case 2 (Smallest K=0): 1×11 \times 1 矩阵,K=0K=0。测试最小边界,结果应等于输入。
    3. Case 3 (Smallest K=1): 1×11 \times 1 矩阵,K=1K=1。虽然范围覆盖出去了,但物理只能采到这一个点,测试边界截断逻辑。
    4. Case 4 (K=0 Identity): N,M=10,K=0N, M=10, K=0。当 K=0K=0 时,采集范围就是自身,输出矩阵应与输入矩阵完全一致。
    5. Case 5 (Full Cover): Kmax(N,M)K \ge \max(N, M)。采集范围覆盖全图,每个点的结果都应该是整个矩阵的总和。测试 max/min 边界处理是否正确。
    6. Case 6 (Row Vector): 1×10001 \times 1000。退化为一维数组,测试 N=1N=1 时的行边界处理。
    7. Case 7 (Col Vector): 1000×11000 \times 1。测试 M=1M=1 时的列边界处理。
    8. Case 8 (Medium Random): 100×100100 \times 100。常规随机数据,检验一般情况下的正确性。
    9. Case 9 (Large Matrix K=1): 1000×1000,K=11000 \times 1000, K=1。大规模数据,主要测试前缀和构建和查询的效率(O(NM)O(NM) vs O(NMK2)O(NMK^2) 的差异)。
    10. Case 10 (Stress Test): 1000×1000,K=5001000 \times 1000, K=500。最大规模压力测试,同时因为 KK 很大且元素最大 100,测试 long long 是否能防止数值溢出(最大和约 106×100=10810^6 \times 100 = 10^8int 其实够用,但用 long long 更保险)。

    如何使用

    1. 保存:将代码保存为 generator.cpp
    2. 编译g++ generator.cpp -o generator -O2
    3. 运行./generator
    4. 结果:当前文件夹下会生成 1.in, 1.out ... 10.in, 10.out。可以直接上传到 OJ 后台。
    • 0
      @ 2025-12-13 0:04:03
      
        /**
       * 题目:能量采集器 (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
      上传者