1 条题解

  • 0
    @ 2025-12-8 22:11:05

    你好!我是你的OI教练。这道题(B3868)是逻辑判断类的基础题,非常适合用来练习字符处理布尔值(True/False)思维

    它不像前两题需要复杂的计算,而是需要像安检员一样,检查字符串里的每一个“乘客”(字符)是否符合规定。


    1. 读题关键词:你的“雷达”响了吗?

    1. “分别判断”
      • 你需要做4次独立的检查:二进制、八进制、十进制、十六进制。
      • 输出是 4 个 01,别漏了空格。
    2. “可能以 0 开头”
      • 这提示我们处理的是字符串,而不是整数。如果是整数,前导0会被忽略,但在这里 01 是合法的。
    3. “GG” -> “0 0 0 0”
      • 样例2给出了关键提示:如果出现了 G 这样超出十六进制范围(0-9, A-F)的字符,那么它连十六进制都不是。
      • 隐含条件:题目说字符串由“数字和大写字母”组成,这意味着可能出现 G-Z 这种无效字符。

    2. 预备知识点

    • 字符范围判断
      • 数字:c >= '0' && c <= '9'
      • 字母:c >= 'A' && c <= 'F' (十六进制专用)
    • 布尔标志位 (Flag)
      • 假设初始是合法的 (true),一旦发现一个坏蛋,立刻变成不合法 (false) 并且可以停止检查。
    • 逻辑“与”关系
      • 一个数要是二进制,必须每一位都是 0 或 1。只要有一位不是,它就完了。

    3. 启发式教学:草稿纸上的推演

    来,我们画一张“安检过滤网”。假设字符串是 SS

    检查通道 (进制) 允许通过的字符名单 判定逻辑 举例: "15A" 举例: "101"
    二进制 '0', '1' 如果发现任何字符不在名单里 \to 0,否则 1 '5'不在 \to 0 全在 \to 1
    八进制 '0' ~ '7' 如果发现字符 >7> '7' 或 是字母 \to 0 'A'不在 \to 0
    十进制 '0' ~ '9' 如果发现字符是字母 \to 0
    十六进制 '0' ~ '9', 'A' ~ 'F' 如果发现字符 >F> 'F' (如 G, H...) \to 0 全在 \to 1

    推演结论: 你需要写四个独立的检查逻辑(或者一个通用的函数),遍历字符串的每一位。

    • 草稿纸写法
      • is_bin = true, is_oct = true, is_dec = true, is_hex = true
      • 读入字符 '1':都没事。
      • 读入字符 '5':is_bin 变成 false。其他没事。
      • 读入字符 'A':is_oct 变成 false, is_dec 变成 falseis_hex 没事。
      • 最后输出这四个变量。

    4. 标准代码 (NOIP C++14)

    /**
     * 题目:B3868 [GESP202309 三级] 进制判断
     * 考点:字符串遍历、字符范围判断
     * 难度:普及- / GESP三级
     */
    
    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    // 检查是否符合二进制
    bool checkBin(string s) {
        for (char c : s) {
            // 二进制只能是 '0' 或 '1'
            if (c != '0' && c != '1') return false;
        }
        return true;
    }
    
    // 检查是否符合八进制
    bool checkOct(string s) {
        for (char c : s) {
            // 八进制只能是 '0' - '7'
            if (c < '0' || c > '7') return false;
        }
        return true;
    }
    
    // 检查是否符合十进制
    bool checkDec(string s) {
        for (char c : s) {
            // 十进制只能是 '0' - '9'
            if (c < '0' || c > '9') return false;
        }
        return true;
    }
    
    // 检查是否符合十六进制
    bool checkHex(string s) {
        for (char c : s) {
            // 十六进制可以是 '0'-'9' 或者 'A'-'F'
            bool isDigit = (c >= '0' && c <= '9');
            bool isHexChar = (c >= 'A' && c <= 'F');
            
            // 如果既不是数字,也不是A-F,那就是非法的(比如 G, H, Z)
            if (!isDigit && !isHexChar) return false;
        }
        return true;
    }
    
    void solve() {
        string s;
        cin >> s;
    
        // 分别调用四个函数进行判断
        // 注意:C++中 true 输出为 1,false 输出为 0,正好符合题目要求
        cout << checkBin(s) << " " 
             << checkOct(s) << " " 
             << checkDec(s) << " " 
             << checkHex(s) << endl;
    }
    
    int main() {
        // IO优化
        ios::sync_with_stdio(false);
        cin.tie(0);
    
        int n;
        if (cin >> n) {
            while (n--) {
                solve();
            }
        }
        return 0;
    }
    

    5. 数据生成器 (1.in - 10.in)

    为了全面测试,我们需要生成包含各种字符组合的数据,特别要注意题目提到的“数字和大写字母”范围,包括无效的 G-Z

    /**
     * B3868 数据生成器
     * 生成 1.in/1.out ~ 10.in/10.out
     */
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <cstdlib>
    #include <ctime>
    #include <algorithm>
    
    using namespace std;
    
    // ==========================================
    // Part 1: 标准题解逻辑 (用于生成 .out)
    // ==========================================
    bool isBin(string s) {
        for (char c : s) if (c != '0' && c != '1') return false;
        return true;
    }
    bool isOct(string s) {
        for (char c : s) if (c < '0' || c > '7') return false;
        return true;
    }
    bool isDec(string s) {
        for (char c : s) if (c < '0' || c > '9') return false;
        return true;
    }
    bool isHex(string s) {
        for (char c : s) {
            if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) return false;
        }
        return true;
    }
    
    // ==========================================
    // Part 2: 数据构造逻辑
    // ==========================================
    int randInt(int min, int max) {
        return rand() % (max - min + 1) + min;
    }
    
    // 字符集定义
    const string CHARS_BIN = "01";
    const string CHARS_OCT = "01234567";
    const string CHARS_DEC = "0123456789";
    const string CHARS_HEX = "0123456789ABCDEF";
    const string CHARS_ALL = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 含非法字符 G-Z
    
    string generateString(int type, int len) {
        string s = "";
        string dictionary;
        
        // type决定了我们主要从哪个字典里取词,构造特定的测试点
        if (type == 2) dictionary = CHARS_BIN;
        else if (type == 8) dictionary = CHARS_OCT;
        else if (type == 10) dictionary = CHARS_DEC;
        else if (type == 16) dictionary = CHARS_HEX;
        else dictionary = CHARS_ALL; // type = 0, 混合乱炖,可能包含 G-Z
        
        for (int i = 0; i < len; i++) {
            s += dictionary[randInt(0, dictionary.length() - 1)];
        }
        return s;
    }
    
    void makeData(int fileId) {
        string inName = to_string(fileId) + ".in";
        string outName = to_string(fileId) + ".out";
        
        ofstream fin(inName);
        ofstream fout(outName);
        
        int N;
        if (fileId <= 2) N = 10;
        else if (fileId <= 5) N = 100;
        else N = 1000;
        
        fin << N << endl;
        
        for (int i = 0; i < N; i++) {
            int len = randInt(1, 10); // 题目保证长度不超过10
            string s;
            
            // 精心设计测试点分布
            if (fileId == 1) {
                // 基础:主要测试纯二进制和纯十进制
                s = generateString(randInt(0, 1) ? 2 : 10, len);
            } else if (fileId == 3) {
                // 专测非法字符:强制混入 G-Z
                s = generateString(0, len); 
                // 强制加个Z确保非法
                s += "Z"; 
                if(s.length() > 10) s.pop_back(); // 保持长度合法
            } else if (fileId == 4) {
                // 专测十六进制 (A-F)
                s = generateString(16, len);
            } else {
                // 随机混合
                int dice = randInt(1, 5);
                if (dice == 1) s = generateString(2, len);
                else if (dice == 2) s = generateString(8, len);
                else if (dice == 3) s = generateString(10, len);
                else if (dice == 4) s = generateString(16, len);
                else s = generateString(0, len); // 完全随机
            }
            
            fin << s << endl;
            
            // 计算 Output
            fout << isBin(s) << " " << isOct(s) << " " << isDec(s) << " " << isHex(s) << endl;
        }
        
        fin.close();
        fout.close();
        cout << "Generated Case " << fileId << " (" << N << " lines)" << endl;
    }
    
    int main() {
        srand((unsigned)time(NULL)); 
        for (int i = 1; i <= 10; i++) {
            makeData(i);
        }
        return 0;
    }
    

    教练总结

    这道题虽然简单,但它是逻辑严密性的试金石。

    1. 包含关系:二进制一定符合八进制要求,八进制一定符合十进制要求(错!八进制是0-7,十进制是0-9,但十进制可能包含8和9,所以八进制数一定是合法的十进制数串,但反之不然)。
      • 修正:如果看作字符串集合:BinStr \subset OctStr \subset DecStr \subset HexStr。所以如果是二进制,后面三个一定都是 1。如果是十进制,后面一定是 1。这道题不需要利用这个性质,直接暴力判断最稳妥。
    2. 边界防御:一定要考虑到 G-Z 这种题目描述中隐含的“捣乱分子”。
    • 1

    信息

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