CF2022D2.Asesino (Hard Version)

省选/NOI-

通过率:0%

AC君温馨提醒

该题目为【codeforces】题库的题目,您提交的代码将被提交至codeforces进行远程评测,并由ACGO抓取测评结果后进行展示。由于远程测评的测评机由其他平台提供,我们无法保证该服务的稳定性,若提交后无反应,请等待一段时间后再进行重试。

题目描述

这是该问题的困难版本。在本版本中,你必须使用尽可能少的询问次数。只有在两个版本都被解决的情况下,你才能进行 Hack。

这是一个交互式问题。

在墨西哥国家 IOI 集训中,有一个传统游戏叫做“Asesino”,它类似于“Among Us”或“Mafia”。

今天,有 nn 名玩家(编号从 11 到 nn)将参与“Asesino”游戏,游戏中有以下三种角色:

  • 骑士(Knight):骑士总是说真话。
  • 恶棍(Knave):恶棍总是说谎。
  • 冒名顶替者(Impostor):冒名顶替者表面上被所有人认为是骑士,实际上却是恶棍。

每个玩家都会被分配一个角色。游戏中恰好有一名冒名顶替者,但骑士和恶棍的人数可以为任意(可能为零)。

作为游戏主持人,你不小心忘记了每个人的角色,但你需要确定谁是冒名顶替者。

为了找出冒名顶替者,你可以提出一些问题。每次提问,你可以选择两个玩家 ii 和 jj(1≤i,j≤n1 \leq i, j \leq n,i≠ji \neq j),并询问玩家 ii 是否认为玩家 jj 是骑士。问题的回答规则如下表所示:

骑士(Knight) 恶棍(Knave) 冒名顶替者(Impostor)
骑士 是 否 是
恶棍 否 是 否
冒名顶替者 否 是 —

表中第 aa 行第 bb 列的回答表示当 ii 的角色为 aa,jj 的角色为 bb 时的回答。例如,第一行第三列的“是”表示当 ii 是骑士,jj 是冒名顶替者时的回答是“是”。

请用最少的询问次数找出冒名顶替者。也就是说,设 f(n)f(n) 为对于 nn 个玩家,存在一种策略最多用 f(n)f(n) 次询问就能确定冒名顶替者。你必须在不超过 f(n)f(n) 次询问内确定冒名顶替者。

注意:评测器是自适应的:玩家的角色在一开始并未固定,可能会根据你的提问动态变化。但保证始终存在一种角色分配方式,使得所有已提问的问题都满足本题的约束。

输入格式

输入的第一行包含一个整数 tt(1≤t≤1031 \leq t \leq 10^3),表示测试用例的数量。接下来是每个测试用例的描述。

每个测试用例的第一行包含一个整数 nn(3≤n≤1053 \leq n \leq 10^5),表示参与游戏的人数。

保证所有测试用例中 nn 的总和不超过 10510^5。

输出格式

每次提问时,输出一行,格式如下:

  • "? i j"(1≤i,j≤n1 \leq i, j \leq n,i≠ji \neq j)——表示询问玩家 ii 是否认为玩家 jj 是骑士。

评测器会返回 "1" 表示玩家 ii 认为玩家 jj 是骑士,返回 "0" 表示不是。

当你确定了冒名顶替者是谁时,输出一行,格式如下:

  • "! i"(1≤i≤n1 \leq i \leq n)——表示第 ii 位玩家是冒名顶替者。

注意,输出答案不计入 f(n)f(n) 次询问的限制。

如果你的输出不合法、询问次数超过 f(n)f(n) 或者错误地确定了冒名顶替者,评测器会返回 "-1",你的程序必须立即终止。否则,你的程序可能会因为读取已关闭的流而收到任意判题结果。

每次输出询问后,别忘了输出换行并刷新输出缓冲区。否则,你会因“Idleness limit exceeded”而被判为超时。具体刷新方法如下:

  • C++:fflush(stdout) 或 cout.flush()
  • Java:System.out.flush()
  • Python:sys.stdout.flush()
  • Rust:stdiostdout().flush()
  • 其它语言请参见相关文档。

Hack 格式

对于 Hack,请使用如下格式。

第一行包含一个整数 tt,表示测试用例数量。

每个测试用例的第一行包含整数 nn 和字符串 "manual"。

第二行包含 nn 个整数 a1,a2,…,ana_1, a_2, \ldots, a_n(−1≤ai≤1-1 \leq a_i \leq 1),表示每个玩家的角色。11 表示骑士,00 表示恶棍,−1-1 表示冒名顶替者。必须恰好有一个 ai=−1a_i = -1。

例如,Hack 输入格式如下:

2
7 manual
0 1 0 -1 0 1 0
4 manual
0 1 -1 0

输入输出样例

  • 输入#1

    2
    7
    
    1
    
    0
    
    0
    
    1
    
    1
    
    0
    
    0
    
    4
    
    0
    
    1
    
    1
    
    1

    输出#1

    ? 1 3
    
    ? 7 6
    
    ? 2 5
    
    ? 6 2
    
    ? 4 5
    
    ? 4 6
    
    ? 1 4
    
    ! 4
    
    ? 1 2
    
    ? 2 3
    
    ? 3 4
    
    ? 4 1
    
    ! 3

说明/提示

注意,示例测试用例并不代表最优的提问策略,仅用于演示交互格式。实际上,通过示例中的提问无法确定冒名顶替者。

在第一个测试用例中,第 22 和第 66 位玩家是骑士,第 11、33、55、77 位玩家是恶棍,第 44 位玩家是冒名顶替者。以下是各次提问的解释:

  • 第一次提问,ii 是恶棍,jj 是恶棍。回答为“是”,因为恶棍总是说谎。
  • 第二次提问,ii 是恶棍,jj 是骑士。回答为“否”,因为恶棍总是说谎。
  • 第三次提问,ii 是骑士,jj 是恶棍。回答为“否”,因为骑士总是说真话。
  • 第四次提问,ii 是骑士,jj 是骑士。回答为“是”,因为骑士总是说真话。
  • 第五次提问,ii 是冒名顶替者,jj 是恶棍。回答为“是”,因为冒名顶替者总是说谎。
  • 第六次提问,ii 是冒名顶替者,jj 是骑士。回答为“否”,因为冒名顶替者总是说谎。
  • 第七次提问,ii 是恶棍,jj 是冒名顶替者。回答为“否”,因为恶棍总是说谎,并且恶棍认为冒名顶替者是骑士。

由 ChatGPT 4.1 翻译

输入解题思路,AI测评打分。不知道怎么写?

首页