2 条题解

  • 0
    @ 2025-12-1 22:33:55

    你好,我是阿西莫夫。

    为了确保你的测试数据既符合科学逻辑,又能经受住评测系统的考验(特别是防止概率下溢变成全零),我为你专门编写了这套带“保底机制”的数据生成器

    这个生成器会自动生成 1.in ~ 10.in 以及对应的标准答案 1.out ~ 10.out

    C++ 数据生成器 (gen_mendel.cpp)

    请将以下代码保存并运行。它包含了标准解答逻辑输入生成逻辑

    /**
     * Project: Mendel's Garden (Data Generator)
     * Author: Isaac Asimov (AI)
     * Features: 
     *   1. Integrates the standard solution to generate .out files.
     *   2. Outputs probabilities with 2 decimal precision.
     *   3. Includes "Easy Mode" for large N to prevent probability underflow (0.00).
     */
    
    #include <iostream>
    #include <fstream>
    #include <random>
    #include <string>
    #include <vector>
    #include <iomanip>
    #include <cctype>
    
    using namespace std;
    
    // ==========================================
    // Part 1: 标准解答逻辑 (The Ground Truth)
    // ==========================================
    class Solution {
        // 判断是否表现为显性
        bool is_dominant(char g1, char g2) {
            return (g1 >= 'A' && g1 <= 'Z') || (g2 >= 'A' && g2 <= 'Z');
        }
    
    public:
        void solve(string in_file, string out_file) {
            ifstream cin(in_file);
            ofstream cout(out_file);
            if (!cin.is_open()) return;
    
            int n;
            if (!(cin >> n)) return;
    
            string s1, s2, t;
            cin >> s1 >> s2 >> t;
    
            double total_prob = 1.0;
    
            for (int i = 0; i < n; i++) {
                char p1a = s1[2 * i];
                char p1b = s1[2 * i + 1];
                char p2a = s2[2 * i];
                char p2b = s2[2 * i + 1];
                
                // 目标是否要求显性
                bool want_dominant = (t[i] >= 'A' && t[i] <= 'Z');
                
                int match_count = 0;
                // 孟德尔棋盘 2x2 枚举
                if (is_dominant(p1a, p2a) == want_dominant) match_count++;
                if (is_dominant(p1a, p2b) == want_dominant) match_count++;
                if (is_dominant(p1b, p2a) == want_dominant) match_count++;
                if (is_dominant(p1b, p2b) == want_dominant) match_count++;
                
                total_prob *= (match_count / 4.0);
            }
    
            // 核心要求:保留 2 位小数
            cout << fixed << setprecision(2) << total_prob << endl;
            
            cin.close();
            cout.close();
            cout << "Generated: " << out_file << endl;
        }
    };
    
    // ==========================================
    // Part 2: 数据生成逻辑
    // ==========================================
    mt19937 rng(2025);
    
    int rand_int(int min, int max) {
        uniform_int_distribution<int> dist(min, max);
        return dist(rng);
    }
    
    // 辅助函数:生成一对等位基因字符串
    // type: 0=隐性纯合(aa), 1=杂合(Aa), 2=显性纯合(AA)
    // base: 基础字符,如 'A'
    string gen_gene_pair(int type, char base) {
        string res = "";
        char upper = toupper(base);
        char lower = tolower(base);
        
        if (type == 0) { // aa
            res += lower; res += lower; 
        } else if (type == 2) { // AA
            res += upper; res += upper; 
        } else { // Aa (随机顺序 Aa 或 aA)
            if (rand_int(0, 1)) { res += upper; res += lower; }
            else { res += lower; res += upper; }
        }
        return res;
    }
    
    void generate_input(int case_id) {
        string filename = to_string(case_id) + ".in";
        ofstream fout(filename);
    
        int n;
        string s1 = "", s2 = "", t = "";
    
        // --- 规模设定 ---
        if (case_id == 1) n = 1;      // 基础
        else if (case_id == 2) n = 2; // 自由组合
        else if (case_id == 3) n = 3; 
        else if (case_id <= 7) n = rand_int(5, 15); // 中等规模
        else n = rand_int(20, 50);    // 大规模 (压力测试)
    
        // --- 基因生成循环 ---
        for (int i = 0; i < n; i++) {
            char base = 'A' + (i % 26); // 使用 A, B, C... 循环
            
            // --- 策略:防止概率下溢 (Underflow Protection) ---
            // 当 N 很大时,如果每对基因的概率都是 0.75 或 0.5,
            // 总概率会迅速变成 0.00000...
            // 为了让测试数据更有趣,我们在 N 较大时,强制让大部分组合变成“必定事件”(概率1.0)
            
            bool force_certainty = false;
            if (n > 10) {
                // 70% 的概率生成“必定事件”,保持总分不掉落
                if (rand_int(1, 100) <= 70) force_certainty = true;
            }
    
            int type1, type2;
            char target;
    
            if (force_certainty) {
                // 构造必定事件: AA x AA -> 显性 (100%)
                type1 = 2; // AA
                type2 = 2; // AA
                target = toupper(base); // 目标: 显性
            } else {
                // 完全随机
                type1 = rand_int(0, 2); // 0, 1, 2
                type2 = rand_int(0, 2);
                // 随机目标
                if (rand_int(0, 1)) target = toupper(base);
                else target = tolower(base);
            }
    
            s1 += gen_gene_pair(type1, base);
            s2 += gen_gene_pair(type2, base);
            t += target;
        }
    
        fout << n << endl;
        fout << s1 << endl;
        fout << s2 << endl;
        fout << t << endl;
    
        fout.close();
    }
    
    int main() {
        // 提升控制台输出速度
        ios_base::sync_with_stdio(false);
    
        cout << "--- Generating Mendel's Garden Data ---" << endl;
        cout << "Target: 2 decimal precision output." << endl;
    
        Solution solver;
        for (int i = 1; i <= 10; i++) {
            generate_input(i);
            string in = to_string(i) + ".in";
            string out = to_string(i) + ".out";
            solver.solve(in, out);
        }
    
        cout << "--- Done! Generated 10 sets of data. ---" << endl;
        return 0;
    }
    

    重点设计说明

    1. 防止全零结果 (force_certainty)

      • 在遗传学概率计算中,如果 N=50N=50,即使每项概率高达 0.90.9,总概率 0.9500.0050.9^{50} \approx 0.005,四舍五入保留两位小数后就是 0.01 甚至 0.00
      • 为了避免后几个测试点全是 0.00(这样学生只要 cout << 0.00 就能骗分),我在 N>10N > 10 的测试点中加入了一个机制:约 70% 的基因对会被生成为 “显性纯合子 x 显性纯合子 \to 目标显性”
      • 这保证了这一项的概率为 1.01.0,从而“托住”了总概率,使其可能维持在 0.10 ~ 0.90 之间,具有区分度。
    2. 严格的格式控制

      • 输入字符串 S1,S2S_1, S_2 长度严格为 2N2N
      • 目标字符串 TT 长度严格为 NN
      • 输出严格保留 2 位小数。

    这套数据生成器现在完美匹配了我们最终定稿的题目描述。祝你的学生们解题愉快!

    • 0
      @ 2025-12-1 22:29:37
      #include <iostream>
      #include <string>
      #include <vector>
      #include <iomanip> // 用于保留小数位
      
      using namespace std;
      
      // 判断一个基因型(两个字符)表现的是显性还是隐性
      // 规则:只要有一个大写字母,就是显性
      bool is_dominant_phenotype(char g1, char g2) {
          bool d1 = (g1 >= 'A' && g1 <= 'Z');
          bool d2 = (g2 >= 'A' && g2 <= 'Z');
          return d1 || d2;
      }
      
      // 计算单对性状符合目标的概率
      double calc_single_prob(char p1_1, char p1_2, char p2_1, char p2_2, char target_type) {
          // 目标是否要求显性?
          bool want_dominant = (target_type >= 'A' && target_type <= 'Z');
      
          int match_count = 0;
          
          // 枚举 2x2 = 4 种杂交组合 (孟德尔棋盘)
          if (is_dominant_phenotype(p1_1, p2_1) == want_dominant) match_count++;
          if (is_dominant_phenotype(p1_1, p2_2) == want_dominant) match_count++;
          if (is_dominant_phenotype(p1_2, p2_1) == want_dominant) match_count++;
          if (is_dominant_phenotype(p1_2, p2_2) == want_dominant) match_count++;
      
          return (double)match_count / 4.0;
      }
      
      int main() {
          // IO 优化
          ios_base::sync_with_stdio(false);
          cin.tie(NULL);
      
          int n;
          if (!(cin >> n)) return 0;
      
          string s1, s2, t;
          cin >> s1 >> s2 >> t;
      
          double total_prob = 1.0;
      
          // 遍历每一对性状
          for (int i = 0; i < n; i++) {
              // 获取第 i 对性状的等位基因
              char p1_a = s1[2 * i];
              char p1_b = s1[2 * i + 1];
              
              char p2_a = s2[2 * i];
              char p2_b = s2[2 * i + 1];
      
              char target = t[i];
      
              // 计算这一对的概率
              double p = calc_single_prob(p1_a, p1_b, p2_a, p2_b, target);
      
              // 独立事件概率相乘
              total_prob *= p;
          }
      
          // 输出保留 2 位小数
          cout << fixed << setprecision(2) << total_prob << endl;
      
          return 0;
      }
      
      • 1

      信息

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