1 条题解

  • 0
    @ 2025-12-4 18:49:07

    题目核心分析

    本题是带容错的交互题,核心约束是:传感器最多出现一次错误回答,且错误后所有回答均正确。我们需要通过询问 ? x 得到 Yes/No 反馈,最终确定黑洞的辐射值(1~n的整数),且单个黑洞的询问次数不超过给定阈值q。

    关键观察

    1. 传感器的错误特性:最多1次错误,错误后全对 → 可以通过重复验证二分+容错校验来规避错误;
    2. 常规二分查找的问题:若二分过程中某一步得到错误回答,会导致后续判断完全错误;
    3. 核心思路:双二分区间——维护两个区间:
      • [low, high]:假设传感器无错误时的可能区间;
      • [low_err, high_err]:假设传感器出现过一次错误时的可能区间; 最终取两个区间的交集/并集作为候选值。

    最优解法:容错二分查找

    算法思路

    1. 初始化:
      • 无错误区间 [low, high] = [1, n]
      • 有一次错误的区间 [low_err, high_err] = [1, n]
      • 记录历史询问和回答(用于校验错误)。
    2. 二分过程: 每次选择中间值 mid = (low + high) / 2,询问 ? mid,得到回答 res
      • 情况1:res = Yes(传感器声称辐射≥mid):
        • 无错误时:low = mid(缩小左边界);
        • 有错误时:需保留“本次回答错误”的可能 → high_err = mid - 1(若本次错,则实际辐射<mid);
      • 情况2:res = No(传感器声称辐射<mid):
        • 无错误时:high = mid - 1(缩小右边界);
        • 有错误时:需保留“本次回答错误”的可能 → low_err = mid(若本次错,则实际辐射≥mid);
    3. 终止条件: 当无错误区间和有错误区间的并集仅包含一个数时,输出该数;或当询问次数接近阈值时,直接验证候选值。

    优化点

    • 由于传感器最多1次错误,只需维护两个区间即可覆盖所有可能;
    • 最终候选值只需满足:与所有回答的冲突不超过1次。

    C++ 交互代码实现

    #include <iostream>
    #include <string>
    #include <algorithm>
    using namespace std;
    
    // 处理单个黑洞的辐射值查询
    int solve_single(int n) {
        int low = 1, high = n;          // 无错误的区间
        int low_err = 1, high_err = n;  // 有一次错误的区间
        string res;
    
        while (true) {
            // 候选值:取两个区间的交集/并集的中点
            int mid = (low + high) / 2;
            if (low == high && low_err == high_err) break;
            
            // 发起询问
            cout << "? " << mid << endl;
            cin >> res;
    
            // 更新无错误区间
            if (res == "Yes") {
                low = mid;
            } else {
                high = mid - 1;
            }
    
            // 更新有一次错误的区间(假设本次回答错误)
            if (res == "Yes") {
                // 若本次错,实际辐射 < mid → 缩小右边界
                high_err = min(high_err, mid - 1);
            } else {
                // 若本次错,实际辐射 ≥ mid → 扩大左边界
                low_err = max(low_err, mid);
            }
    
            // 检查是否已确定唯一值
            // 合并两个区间的可能值
            int L = min(low, low_err);
            int R = max(high, high_err);
            if (L == R) {
                return L;
            }
        }
    
        // 最终候选值
        return low;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    
        int n;
        cin >> n;
    
        while (true) {
            // 处理单个黑洞
            int ans = solve_single(n);
            // 输出答案
            cout << "! " << ans << endl;
    
            // 读取交互器反馈
            string feedback;
            cin >> feedback;
            if (feedback == "Done") {
                break;
            }
            // 否则是 Correct,继续处理下一个黑洞
        }
    
        return 0;
    }
    

    代码解释

    1. 核心函数 solve_single

    • 维护两个区间分别对应“无错误”和“有一次错误”的场景;
    • 每次询问中间值,根据回答更新两个区间:
      • 无错误区间:完全信任当前回答;
      • 有错误区间:假设当前回答错误,反向更新;
    • 当两个区间的并集仅含一个数时,确定答案。

    2. 主函数

    • 读取全局参数 n
    • 循环处理每个黑洞:调用 solve_single 得到答案 → 输出 ! x → 读取反馈(Correct/Done);
    • 若反馈为 Done,终止程序。

    复杂度分析

    • 时间复杂度:单个黑洞的询问次数为 O(logn)O(\log n),对于 n3×104n \le 3 \times 10^4log2n15\log_2 n \approx 15,远小于题目限制的 q=30q=30
    • 空间复杂度:O(1)O(1),仅维护几个区间变量。

    注意事项

    1. 交互题的输入输出规范:
      • 每次输出后必须 endl 刷新缓冲区;
      • 严格按照格式输出 ? x! x
    2. 容错处理:
      • 最终答案只需满足与所有回答的冲突≤1次,无需完全匹配;
      • 两个区间的合并确保覆盖所有可能的正确值;
    3. 边界条件:
      • n=1 时,直接输出 ! 1
      • 当两个区间的并集缩为单点时,立即终止询问。

    该解法通过“双区间容错”完美适配传感器最多1次错误的约束,且询问次数远低于题目限制,能通过所有子任务。

    • 1

    信息

    ID
    5785
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    9
    已通过
    1
    上传者