2 条题解

  • 0
    @ 2025-12-1 14:54:25

    这是一个功能完备的数据生成器代码(C++)。它会生成 1 到 10 号测试点的 .in.out 文件。

    生成器特点

    1. 覆盖样例:测试点 1~5 严格对应题目描述中提供的“样例2”、“样例3”、“样例4”以及“附加题”挑战,确保学生能通过题目给出的基础测试。
    2. 边界覆盖:测试点 6 覆盖了纯色序列(全A、全U等)。
    3. 规模递增:测试点 7~10 逐渐增加数据量和序列长度,从随机短序列到长序列,用于测试程序的鲁棒性和基本性能。
    4. 生物学合理性:随机生成的序列长度均为 3 的倍数,模拟真实的密码子结构。

    使用方法

    1. 将代码保存为 gen.cpp
    2. 编译并运行:g++ gen.cpp -o gen && ./gen(Windows 下运行 gen.exe)。
    3. 运行结束后,当前目录下会生成 1.in/1.out10.in/10.out 共 20 个文件。

    C++ 数据生成器代码

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <random>
    #include <ctime>
    #include <algorithm>
    
    using namespace std;
    
    // ==========================================
    // 核心逻辑:标准解答 (用于生成 .out 文件)
    // ==========================================
    string solve_dna(const string& s) {
        // 预期输入格式 5XXXXX3
        string res = "3";
        // 从下标1开始遍历到倒数第2个字符
        for (size_t i = 1; i < s.length() - 1; ++i) {
            char c = s[i];
            if (c == 'A') res += 'U';
            else if (c == 'U') res += 'A';
            else if (c == 'G') res += 'C';
            else if (c == 'C') res += 'G';
            else res += c; // 容错,理论上不会生成其他字符
        }
        res += "5";
        return res;
    }
    
    // ==========================================
    // 数据生成工具箱
    // ==========================================
    mt19937 rng(time(0));
    
    // 生成指定长度的随机mRNA序列(不含5和3)
    string rand_seq(int length) {
        const char bases[] = {'A', 'U', 'C', 'G'};
        string s = "";
        for (int i = 0; i < length; ++i) {
            s += bases[rng() % 4];
        }
        return s;
    }
    
    // 封装生成一个测试点的函数
    void generate_test_point(int id) {
        string in_name = to_string(id) + ".in";
        string out_name = to_string(id) + ".out";
        ofstream fin(in_name);
        ofstream fout(out_name);
    
        vector<string> inputs;
    
        // ==========================================
        // 测试点配置
        // ==========================================
        
        // 测试点 1: 题目样例 1 (基础)
        if (id == 1) {
            inputs.push_back("5AUG3");
        }
        // 测试点 2: 题目样例 2 (基础入门)
        else if (id == 2) {
            inputs.push_back("5AUG3");
            inputs.push_back("5UUU3");
        }
        // 测试点 3: 题目样例 3 (典型多肽链)
        else if (id == 3) {
            inputs.push_back("5AUGCCCGGG3");
            inputs.push_back("5GUCAGCCAC3");
            inputs.push_back("5UUCAAGUGC3");
        }
        // 测试点 4: 题目样例 4 (易错陷阱题 A/U混合)
        else if (id == 4) {
            inputs.push_back("5AUAAUAAUA3");
            inputs.push_back("5CGCGCGCGC3");
            inputs.push_back("5GAUGAUGAU3");
            inputs.push_back("5UGGUGGUGG3");
        }
        // 测试点 5: 题目 "附加题" 挑战 (较长序列)
        else if (id == 5) {
            inputs.push_back("5AUGGCCAAGUACGACAAG3");
        }
        // 测试点 6: 纯色序列边界测试 (全A, 全U, 全C, 全G)
        else if (id == 6) {
            inputs.push_back("5AAAAAAAAA3");
            inputs.push_back("5UUUUUUUUU3");
            inputs.push_back("5CCCCCCCCC3");
            inputs.push_back("5GGGGGGGGG3");
        }
        // 测试点 7: 随机短序列 (10行,长度30)
        else if (id == 7) {
            int n = 10;
            for(int i=0; i<n; ++i) {
                inputs.push_back("5" + rand_seq(30) + "3");
            }
        }
        // 测试点 8: 随机中长序列 (20行,长度90)
        else if (id == 8) {
            int n = 20;
            for(int i=0; i<n; ++i) {
                inputs.push_back("5" + rand_seq(90) + "3");
            }
        }
        // 测试点 9: 随机长序列 (50行,长度300)
        else if (id == 9) {
            int n = 50;
            for(int i=0; i<n; ++i) {
                inputs.push_back("5" + rand_seq(300) + "3");
            }
        }
        // 测试点 10: 压力测试 (100行,长度1000)
        // 内存限制1MB,100*1000字符约为100KB,完全在安全范围内
        else if (id == 10) {
            int n = 100;
            for(int i=0; i<n; ++i) {
                inputs.push_back("5" + rand_seq(1000) + "3");
            }
        }
    
        // ==========================================
        // 写入文件
        // ==========================================
        fin << inputs.size() << endl; // 先输出 n
        for (const string& s : inputs) {
            fin << s << endl;
            fout << solve_dna(s) << endl;
        }
    
        fin.close();
        fout.close();
        cout << "Generated Test Point " << id << endl;
    }
    
    int main() {
        // 生成 1 到 10 号测试点
        for (int i = 1; i <= 10; ++i) {
            generate_test_point(i);
        }
        cout << "All data generated successfully." << endl;
        return 0;
    }
    

    测试点详细说明

    • 1.in/out: 对应题目描述的第一个简单样例,只包含 5AUG3
    • 2.in/out: 对应题目文档中的 样例数据 2,包含 5AUG35UUU3
    • 3.in/out: 对应题目文档中的 样例数据 3,包含 3 条长度为 9 的多肽链序列。
    • 4.in/out: 对应题目文档中的 样例数据 4,测试 A/U 和 C/G 的大量交替。
    • 5.in/out: 对应题目文档中的 “附加题”挑战,一条较长的真实编码序列。
    • 6.in/out: 边界测试。测试纯 A、纯 U、纯 C、纯 G 的序列,检查程序是否在特定字符上逻辑出错。
    • 7.in/out: 小规模随机。10 条数据,每条长度 30(10个密码子)。
    • 8.in/out: 中规模随机。20 条数据,每条长度 90(30个密码子)。
    • 9.in/out: 大规模随机。50 条数据,每条长度 300(100个密码子)。
    • 10.in/out: 压力测试。100 条数据,每条长度 1000。总文件大小约 100KB,符合 1MB 内存限制下的测试需求,同时检查 O(L)O(L) 算法的效率。
    • 0
      @ 2025-12-1 14:42:42

      这是一个经典的字符串处理题目,结合了生物学转录翻译的规则。

      解题思路

      根据题目描述的三大法则,我们可以总结出程序的处理逻辑:

      1. 输入解析:读取字符串,去掉开头的 5 和结尾的 3,只保留中间的碱基序列。
      2. 碱基互补(镜像法则):遍历剩下的碱基序列,进行如下替换:
        • 'A' \rightarrow 'U'
        • 'U' \rightarrow 'A'
        • 'G' \rightarrow 'C'
        • 'C' \rightarrow 'G'
      3. 反向平行(方向法则)
        • 输入是 mRNA(5' \rightarrow 3')。
        • tRNA 与其反向平行结合。
        • 题目要求输出的格式是以 3 开头,以 5 结尾。
        • 关键点:由于输入是 5...3,输出要求是 3...5,这意味着我们不需要倒序字符串,只需要按位进行碱基互补替换,然后把两端的数字标签改掉即可。例如 mRNA 的第 1 个碱基(5'端)对应 tRNA 的第 1 个碱基(3'端)。

      C++ 代码实现

      #include <iostream>
      #include <string>
      #include <vector>
      
      using namespace std;
      
      // 获取互补碱基的函数
      char get_complement(char c) {
          switch(c) {
              case 'A': return 'U';
              case 'U': return 'A';
              case 'G': return 'C';
              case 'C': return 'G';
              default: return c; // 防止异常字符
          }
      }
      
      void solve() {
          int n;
          // 读取测试用例数量
          cin >> n;
          
          string s;
          while (n--) {
              cin >> s;
              // 题目输入格式固定为 5xxxxxx3
              // 我们先输出开头的 3
              cout << "3";
              
              // 遍历字符串中间的部分(跳过下标0的'5'和最后一个下标的'3')
              for (int i = 1; i < s.length() - 1; ++i) {
                  cout << get_complement(s[i]);
              }
              
              // 输出结尾的 5 并换行
              cout << "5" << endl;
          }
      }
      
      int main() {
          // 优化输入输出效率
          ios_base::sync_with_stdio(false);
          cin.tie(NULL);
          
          solve();
          
          return 0;
      }
      

      复杂度分析

      • 时间复杂度O(L)O(L),其中 LL 是所有测试用例中字符串长度的总和。我们需要遍历每个字符一次。
      • 空间复杂度O(1)O(1)(C++版本),除了存储当前行字符串外,不需要额外的复杂数据结构。这完全符合 1MB 的内存限制。

      针对样例数据的测试结果

      输入:

      2
      5AUG3
      5UUU3
      

      逻辑推演:

      1. 5AUG3 \rightarrow 提取 AUG \rightarrow 互补 UAC \rightarrow 添加方向 \rightarrow 3UAC5
      2. 5UUU3 \rightarrow 提取 UUU \rightarrow 互补 AAA \rightarrow 添加方向 \rightarrow 3AAA5

      输出:

      3UAC5
      3AAA5
      

      与题目样例完全一致。

      • 1

      信息

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