AT2348 [ARC070D] HonestOrUnkind
不妨先从无解的情况下手,不难发现当 \(A \le B\) 时是一定无解的。
因为不诚实的 \(B\) 个人可以装作是诚实的,全部说自己这一方是诚实的对方是不诚实的我们就无法判断了。
下面我们就可以在 \(A > B\) 的情况下来处理这个交互问题了。
一个最基本最靠谱的方法是先找到一个诚实的人,然后用他把所有人全部问一遍。
因此下面我们的目的就是在 \(n\) 次询问以内找到一个诚实的人。
首先需要一个基于操作的观察:
若回答为 \(F\) 则两者之中必然存在一个人不诚实。
那么我们可以考虑使用这一条性质,将不诚实的人排除开来这样剩下的就是诚实的人了。
于此同时,因为我们只知道两者其一必不诚实,因此我们只能一次将两人一起排除。
并且,由于一次排除至多排除一个诚实的人,又 \(A > B\) 所以最终剩下的人一定是诚实的。
那么接下来的目的就是在 \(n\) 次内快速找到 \(B\) 组回答为 \(F\) 的人。
首先不难发现一个查询次数 \(n ^ 2\) 的暴力,每次取出一个没有被排除的人,用所有人询问他一次,正确性显然。
但是给予我们的询问上限是 \(n\) 次,但同时因为每个点至少要被询问一次,因为至少要保证每个不诚实的人都被至少查询一次(因为问不诚实的人的答案是不确定的)。
同时上限是 \(n\),所以我们只能让每个点被恰好被询问一次。
考虑用每个点恰好被询问一次来优化上面哪个暴力的做法。
首先还是先取出一个人来,用另一个人来询问他,如果询问结果为 \(F\) 那么把两人删去,继续递归这个操作;否则我们只能选择让这两个人都留下来,因为无法确定两者中是否存在不诚实的人,再往下递归。
同时因为每个点只能被查询一次,因此递归的时候只能让后面的人查询之前的查询者。
那么最终必然剩下的就是一条查询链,其中每个查询答案均为 \(T\)。
再来观察一下这条查询链,其中必然存在至少一个诚实的人,因为弹出次数最多为 \(B\) 显然 \(A > B\) 所以必然至少有一个诚实的人。
同时,你会发现这个查询链的最前端必然是诚实的人。
否则找到最靠前的哪个诚实的人,他必然能带走之前哪个不诚实的人并一起弹走。
这样我们就在 \(n\) 次查询内找到了一个诚实的人。
可以发现的是上面的这个做法本质上就是一个弹栈和入栈的过程,用栈实现即可。
复杂度 \(O(n)\)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 4000 + 5;
char s[5];
int n, A, B, top, st[N], ans[N];
int read() {
char c; int x = 0, f = 1;
c = getchar();
while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int main() {
A = read(), B = read(), n = A + B;
if(A <= B) { puts("Impossible"); return 0;}
rep(i, 1, n) {
if(!top) st[++top] = i;
else {
printf("? %d %d\n", i - 1, st[top] - 1), cout.flush();
scanf("%s", s + 1);
if(s[1] == 'Y') st[++top] = i;
else --top;
}
}
rep(i, 1, n) {
printf("? %d %d\n", st[1] - 1, i - 1), cout.flush();
scanf("%s", s + 1);
ans[i] = (s[1] == 'Y');
}
printf("! ");
rep(i, 1, n) printf("%d", ans[i]);
return 0;
}
AT2348 [ARC070D] HonestOrUnkind的更多相关文章
- AT2348 HonestOrUnkind
传送门 显然\(a>b\)的情况下才有解 考虑先找出一个诚实的人,然后剩下的都可以在\(n\)次以内问出来了 发现如果一个人说另一个人是说谎的那么这两个人必有一个是说谎的,由于诚实的人严格多于不 ...
- [atARC070F]HonestOrUnkind
考虑当$a\le b$时,构造两种方案,满足诚实的人不交,接下来要求对于任意询问,这两种方案的答案都有可能相同 考虑询问$(i,j)$,若$i$在两种方案中有一种不诚实,那么总可以让答案相同,又因为诚 ...
- AtCoder瞎做第二弹
ARC 067 F - Yakiniku Restaurants 题意 \(n\) 家饭店,\(m\) 张餐票,第 \(i\) 家和第 \(i+1\) 家饭店之间的距离是 \(A_i\) ,在第 \( ...
- AtCoder刷题记录
构造题都是神仙题 /kk ARC066C Addition and Subtraction Hard 首先要发现两个性质: 加号右边不会有括号:显然,有括号也可以被删去,答案不变. \(op_i\)和 ...
- 【AtCoder】ARC070
ARC070 C - Go Home 题目大意:一只袋鼠第i秒可以向左或向右跳i步或者不跳,问从0跳到x的最小时间 就是1,2,3,4...k总和超过x的最小的k,因为如果超过了x的那部分需要减掉的那 ...
随机推荐
- AOP 日志切面
AOP把软件的功能模块分为两个部分:核心关注点和横切关注点.业务处理的主要功能为核心关注点,而非核心.需要拓展的功能为横切关注点.AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点进行分 ...
- Redis 的 3 种集群方案对比
数据持久化 主从复制 自动故障恢复 集群化 数据持久化本质上是为了做数据备份,有了数据持久化,当Redis宕机时,我们可以把数据从磁盘上恢复回来,但在数据恢复之前,服务是不可用的,而且数据恢复的时间取 ...
- 第二十七个知识点:什么是对称密码加密的AEAD安全定义?
第二十七个知识点:什么是对称密码加密的AEAD安全定义? AEAD 在之前的博客里,Luke描述了一种被广泛使用的操作模式(ECB,CBC和CTR)对块密码.我们也可能会想我们加密方案的完整性,完整性 ...
- LDAP理解要点
1.介绍 LDAP(Lightweight Directory Access Protocol)是"轻量级目录访问协议", 是一个用于访问"目录服务器"(Dir ...
- Snack3 3.2 发布,轻量的Json+Jsonpath框架
Snack3 是一个轻量的 JSON + Jsonpath 框架. 借鉴了 Javascript 所有变量由 var 申明,及 Xml dom 一切都是 Node 的设计.其下一切数据都以ONode表 ...
- vue 多级路由嵌套后打开页面是空白
在多层路由嵌套时,一级子目录必须有一个页面并且添加一具<router-view>,否则路由跳转页面为空,没有任何显示 来自为知笔记(Wiz)
- centos7 date时间命令
date "+%F %T" %F full date; same as %Y-%m-%d --相当于年月日格式 %T time; same as %H:%M:%S ...
- Servlet初级学习加入数据库操作(二)
源代码地址:https://url56.ctfile.com/f/34653256-527822631-2e255a(访问密码:7567) 将页面中的数据逐步替换为数据库管理 准备一个连接数据库的类 ...
- 论文翻译:2020_RESIDUAL ACOUSTIC ECHO SUPPRESSION BASED ON EFFICIENT MULTI-TASK CONVOLUTIONAL NEURAL NETWORK
论文翻译:https://arxiv.53yu.com/abs/2009.13931 基于高效多任务卷积神经网络的残余回声抑制 摘要 在语音通信系统中,回声会降低用户体验,需要对其进行彻底抑制.提出了 ...
- 《剑指offer》面试题52. 两个链表的第一个公共节点
问题描述 输入两个链表,找出它们的第一个公共节点. 如下面的两个链表: 在节点 c1 开始相交. 示例 1: 输入:intersectVal = 8, listA = [4,1,8,4,5], lis ...