2 条题解

  • 0
    @ 2025-12-15 10:39:51

    这是一个功能完整的数据生成器代码(generator.cpp)。它会根据题目要求生成 10 组测试数据(1.in/1.out10.in/10.out),覆盖了 N=1N=1M=2M=2 的特殊子任务,以及全正/全负变化值、极限数据范围等各种边界情况。

    数据生成器代码

    你可以将以下代码保存为 generator.cpp,编译并运行即可。

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <random>
    #include <algorithm>
    #include <chrono>
    
    using namespace std;
    
    typedef long long ll;
    
    // ==========================================
    // 1. 标准解法函数 (用于生成 .out 文件)
    // ==========================================
    ll solve(int n, int m, const vector<int>& c, const vector<int>& a) {
        if (n == 1) {
            // 情况 1: 只有一种武器,必须承担所有结果
            ll ans = c[0];
            for (int val : a) {
                ans += val;
            }
            return ans;
        } else {
            // 情况 2: 有多种武器
            // 策略: 选初始值最大的作为主力,只接受正向增益
            // 所有负向或0的增益交给其他武器承担
            int max_c = -200000; // 题目范围 -10000,设置个足够小的初始值
            for (int val : c) {
                if (val > max_c) max_c = val;
            }
            
            ll ans = max_c;
            for (int val : a) {
                if (val > 0) {
                    ans += val;
                }
            }
            return ans;
        }
    }
    
    // ==========================================
    // 2. 随机数生成器初始化
    // ==========================================
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    
    int rand_int(int min, int max) {
        uniform_int_distribution<int> dist(min, max);
        return dist(rng);
    }
    
    // ==========================================
    // 3. 测试点生成逻辑
    // ==========================================
    void generate_case(int id) {
        int n, m;
        int c_min = -100, c_max = 100;
        int a_min = -100, a_max = 100;
    
        // 根据测试点编号配置参数,覆盖所有子任务
        switch (id) {
            case 1: 
                // 子任务 1: n = 1, 小数据
                n = 1; m = 10; 
                break;
            case 2: 
                // 子任务 1: n = 1, 大数据,且变化值偏负
                n = 1; m = 100000; 
                a_min = -100; a_max = 50; 
                break;
            case 3: 
                // 子任务 2: m = 2, n 较小
                n = 10; m = 2; 
                break;
            case 4: 
                // 子任务 2: m = 2, n 很大
                n = 100000; m = 2; 
                break;
            case 5: 
                // 子任务 3: 一般情况, 变化值全为正 (贪心策略测试)
                n = 100; m = 100; 
                a_min = 1; a_max = 100; 
                break;
            case 6: 
                // 子任务 3: 一般情况, 变化值全为负 (贪心策略测试: 应完全避开)
                n = 100; m = 100; 
                a_min = -100; a_max = -1; 
                break;
            case 7: 
                // 子任务 3: n = 2 (最小的多武器情况), 大数据 m
                n = 2; m = 100000; 
                break;
            case 8: 
                // 子任务 3: n 很大, m 较小
                n = 100000; m = 100; 
                break;
            case 9: 
                // 子任务 3: 满级数据, 随机
                n = 100000; m = 100000; 
                break;
            case 10: 
                // 子任务 3: 满级数据, 极限数值范围 (-10000 到 10000)
                n = 100000; m = 100000; 
                c_min = -10000; c_max = 10000;
                a_min = -10000; a_max = 10000;
                break;
            default:
                n = 10; m = 10;
                break;
        }
    
        // 生成数据
        vector<int> c(n);
        vector<int> a(m);
    
        for (int i = 0; i < n; ++i) c[i] = rand_int(c_min, c_max);
        for (int i = 0; i < m; ++i) a[i] = rand_int(a_min, a_max);
    
        // 计算标准答案
        ll ans = solve(n, m, c, a);
    
        // 写入 .in 文件
        string in_file = to_string(id) + ".in";
        ofstream fin(in_file);
        fin << n << " " << m << "\n";
        for (int i = 0; i < n; ++i) fin << c[i] << (i == n - 1 ? "" : " ");
        fin << "\n";
        for (int i = 0; i < m; ++i) fin << a[i] << (i == m - 1 ? "" : " ");
        fin << "\n";
        fin.close();
    
        // 写入 .out 文件
        string out_file = to_string(id) + ".out";
        ofstream fout(out_file);
        fout << ans << "\n";
        fout.close();
    
        cout << "Generated Case " << id << ": n=" << n << ", m=" << m << " -> Done." << endl;
    }
    
    int main() {
        // 生成 1 到 10 号测试点
        for (int i = 1; i <= 10; ++i) {
            generate_case(i);
        }
        return 0;
    }
    

    测试点覆盖说明

    1. 测试点 1: n=1n=1,规模小。测试当无法选择武器时的基本累加逻辑。
    2. 测试点 2: n=1n=1,规模大 (m=105m=10^5)。测试大数据量下 n=1n=1 的情况。
    3. 测试点 3: m=2m=2,规模小。覆盖子任务 2 的基本情况。
    4. 测试点 4: m=2m=2,规模大 (n=105n=10^5)。测试在大量武器中选最大值,只打两场。
    5. 测试点 5: n>1n>1,且所有 ai>0a_i > 0。测试贪心逻辑是否正确累加了所有正收益。
    6. 测试点 6: n>1n>1,且所有 ai<0a_i < 0。测试贪心逻辑是否正确避开了所有负收益(答案应仅为 max(ci)\max(c_i))。
    7. 测试点 7: n=2n=2 (多武器的边界),m=105m=10^5。测试只有一把“废弃”武器时能否正确承担所有负面效果。
    8. 测试点 8: n=105,m=100n=10^5, m=100。测试初始查找最大值的效率。
    9. 测试点 9: n=105,m=105n=10^5, m=10^5。综合随机大数据测试。
    10. 测试点 10: n=105,m=105n=10^5, m=10^5,数值取到题目极限 ±10000\pm 10000。测试 long long 是否必要以及边界数值处理。

    使用方法

    1. 将代码保存为 generator.cpp
    2. 使用 C++ 编译器编译:g++ generator.cpp -o generator -O2
    3. 运行生成的可执行文件:./generator (Windows 下为 generator.exe)。
    4. 运行结束后,当前目录下会出现 1.in ~ 10.in1.out ~ 10.out 共 20 个文件。
    • 0
      @ 2025-12-15 10:37:36

      这是一个经典的贪心算法问题。我们需要根据武器的数量 nn 分两种情况进行讨论。

      题目分析

      我们的目标是最大化最终所有武器熟练度中的最大值

      情况一:只有 1 种武器 (n=1n = 1) 如果只有一种武器,无论每场战斗后熟练度是增加还是减少,小杨都别无选择,必须使用这把武器参加所有 mm 场战斗。 因此,最终熟练度就是:初始熟练度 + 所有战斗的变化值之和。 即:ans=c1+j=1majans = c_1 + \sum_{j=1}^m a_j

      情况二:有多种武器 (n2n \ge 2) 如果有多种武器,我们可以采取“弃车保帅”的策略。为了让某一把武器的熟练度尽可能高,我们应该:

      1. 选定一把初始熟练度最高的武器作为“主力”。
      2. 对于那些能提高熟练度(aj>0a_j > 0)的战斗,全部安排给这把主力武器。
      3. 对于那些会降低或维持熟练度(aj0a_j \le 0)的战斗,既然我们只关心最大值,我们可以把这些“坏”战斗全部安排给除主力以外的其他任意一把武器(“废弃”武器)。因为只要有至少两把武器,我们就总能找到一把不是主力的武器来承担这些负面效果,从而保护主力武器的数值不被拉低。

      因此,在这种情况下,最大可能的熟练度是:所有初始熟练度中的最大值 + 所有正数变化值之和。 即:$ans = \max(c_1, \dots, c_n) + \sum_{j=1}^m \max(0, a_j)$。

      C++ 代码实现

      #include <iostream>
      #include <vector>
      #include <algorithm>
      
      using namespace std;
      
      int main() {
          // 优化输入输出效率
          ios_base::sync_with_stdio(false);
          cin.tie(NULL);
      
          int n, m;
          if (cin >> n >> m) {
              long long max_c; // 记录初始熟练度的最大值
              long long c1;    // 记录第一把武器的熟练度(用于 n=1 的情况)
              
              // 读取初始熟练度
              for (int i = 0; i < n; ++i) {
                  long long val;
                  cin >> val;
                  if (i == 0) {
                      c1 = val;
                      max_c = val;
                  } else {
                      if (val > max_c) {
                          max_c = val;
                      }
                  }
              }
      
              long long sum_a = 0;     // 所有变化值的和
              long long pos_sum_a = 0; // 所有正变化值的和
      
              // 读取战斗变化值
              for (int i = 0; i < m; ++i) {
                  long long val;
                  cin >> val;
                  sum_a += val;
                  if (val > 0) {
                      pos_sum_a += val;
                  }
              }
      
              if (n == 1) {
                  // 只有一种武器,必须承担所有战斗
                  cout << c1 + sum_a << endl;
              } else {
                  // 多种武器,主力武器只打能加熟练度的战斗,负面战斗交给其他武器
                  cout << max_c + pos_sum_a << endl;
              }
          }
          return 0;
      }
      
      • 1

      信息

      ID
      15699
      时间
      1000ms
      内存
      32MiB
      难度
      3
      标签
      递交数
      1
      已通过
      1
      上传者