[CF1526F] Median Queries(交互 / 构造)
题面
这是一道交互题。
有一个未知的长度为
N
\tt N
N 的排列
P
\tt P
P,已知
P
1
<
P
2
\tt P_1 < P_2
P1<P2 。
每次询问格式为 “
?
a
b
c
\tt?~a~b~c
? a b c ”,返回值为三元组
{
∣
P
a
−
P
b
∣
,
∣
P
b
−
P
c
∣
,
∣
P
a
−
P
c
∣
}
\tt \{|P_a-P_b|,|P_b-P_c|,|P_a-P_c|\}
{∣Pa−Pb∣,∣Pb−Pc∣,∣Pa−Pc∣} 的中位数。
在至多
2
n
+
420
\tt 2n+420
2n+420 次询问后,输出排列
P
\tt P
P,格式为 “
!
P
1
P
2
…
P
N
\tt!~P_1~P_2~\dots~P_N
! P1 P2 … PN ”。
然后每组数据会返回一个数,为
1
\tt1
1 则答案正确,为
−
1
\tt-1
−1 则错误,不要忘了输入这个数。
一共
t
(
1
≤
t
≤
1000
)
\tt t(1\leq t\leq1000)
t(1≤t≤1000) 组数据,保证
20
≤
N
≤
1
0
5
,
∑
N
≤
1
0
5
20\leq N\leq 10^5,\tt \sum N\leq 10^5
20≤N≤105,∑N≤105。
题解
有两种各占优势的做法。
Solution #1
首先,返回该三元组的中位数,相当于:若
P
a
>
P
b
>
P
c
\tt P_a>P_b>P_c
Pa>Pb>Pc,则返回
max
{
P
a
−
P
b
,
P
b
−
P
c
}
\tt\max\{P_a-P_b,P_b-P_c\}
max{Pa−Pb,Pb−Pc}。
有了这个简化,才能更好地继续推。
该解法的核心在于:如果已经知道了
1
\tt1
1 和
2
\tt2
2 的位置(假设为
P
A
,
P
B
\tt P_A,P_B
PA,PB),那么可以在
n
−
2
\tt n-2
n−2 次操作后,确定整个排列。也就是分别询问
{
A
,
B
,
i
}
\tt\{A,B,i\}
{A,B,i},所得值(
q
u
e
r
y
(
A
,
B
,
i
)
\tt query(A,B,i)
query(A,B,i))
+
2
\tt+2
+2 便是
P
i
\tt P_i
Pi 了。
问题是怎么获得
1
\tt1
1 和
2
\tt2
2 的位置,或者说,也可以获得
N
\tt N
N 和
N
−
1
\tt N-1
N−1 的位置,总之通过
P
1
<
P
2
\tt P_1<P_2
P1<P2 确定最终答案。
经过一段尝试,我们发现,如果找到这么两个位置
a
\tt a
a 和
b
\tt b
b ,满足
∣
P
a
−
P
b
∣
≤
N
−
4
3
\tt|P_a-P_b|\leq \frac{N-4}{3}
∣Pa−Pb∣≤3N−4 ,处理出所有的
q
[
i
]
=
q
u
e
r
y
(
a
,
b
,
i
)
\tt q[i]=query(a,b,i)
q[i]=query(a,b,i) ,那么
q
[
i
]
\tt q[i]
q[i] 最大的
i
\tt i
i 就是
1
\tt1
1 或者
N
\tt N
N 的位置,
q
[
i
]
\tt q[i]
q[i] 严格次大的
i
\tt i
i 就是
2
\tt2
2 或者
N
−
1
\tt N-1
N−1 的位置。这样只需要多进行
N
−
2
\tt N-2
N−2 次操作。
那么,在剩下的
424
\tt424
424 次操作内,我们需要解决两个问题:
- 找到这样的位置
a
,
b
\tt a,b
a,b 。
- 找到
1
\tt1
1 和
2
\tt2
2 的或者
N
\tt N
N 和
N
−
1
\tt N-1
N−1 的位置
A
,
B
\tt A,B
A,B 。
找 a b:
我们可以证明:对于任意
13
\tt13
13 个位置,总存在
3
\tt3
3 个位置
x
,
y
,
z
\tt x,y,z
x,y,z ,满足
q
u
e
r
y
(
x
,
y
,
z
)
≤
n
−
4
6
\tt query(x,y,z)\leq\frac{n-4}{6}
query(x,y,z)≤6n−4(
⇒
max
{
∣
P
x
−
P
y
∣
,
∣
P
y
−
P
z
∣
,
∣
P
x
−
P
z
∣
}
≤
n
−
4
3
\tt\Rightarrow \max\{|P_x-P_y|,|P_y-P_z|,|P_x-P_z|\}\leq\frac{n-4}{3}
⇒max{∣Px−Py∣,∣Py−Pz∣,∣Px−Pz∣}≤3n−4)。
可以用反证法进行证明,即假设存在某
13
\tt13
13 个位置,满足
∀
{
x
,
y
,
z
}
,
max
{
∣
P
x
−
P
y
∣
,
∣
P
y
−
P
z
∣
,
∣
P
x
−
P
z
∣
}
>
n
−
4
3
\tt\forall \{x,y,z\},\max\{|P_x-P_y|,|P_y-P_z|,|P_x-P_z|\}>\frac{n-4}{3}
∀{x,y,z},max{∣Px−Py∣,∣Py−Pz∣,∣Px−Pz∣}>3n−4 。贪心地填数进去,你就会发现,刚好到
13
\tt13
13 个时,你就满足不了条件了。所以这种情况不存在,假设不成立。
找这
3
\tt3
3 个位置,需要枚举
(
13
3
)
=
286
\tt{13\choose3}=286
(313)=286 种情况,完全足够。
找到这样的
3
\tt3
3 个位置时,任选两个就可以作
a
,
b
\tt a,b
a,b 了。
找 A B:
我们会发现,假如你确定了某个
q
[
i
]
\tt q[i]
q[i] 最大的
A
\tt A
A 作为
1
\tt1
1 的位置,那么还是有两个位置可能为
2
\tt2
2 ,一个是真
2
\tt2
2 ,一个是
N
−
1
\tt N-1
N−1 ,令其分别为
B
1
,
B
2
\tt B_1,B_2
B1,B2 ,我们稍稍归纳一下就会发现:
q
u
e
r
y
(
A
,
B
1
,
a
)
≤
q
u
e
r
y
(
A
,
B
2
,
a
)
q
u
e
r
y
(
A
,
B
1
,
b
)
≤
q
u
e
r
y
(
A
,
B
2
,
b
)
{\tt query(A,B_1,a)\leq query(A,B_2,a)}\\ {\tt query(A,B_1,b)\leq query(A,B_2,b)}
query(A,B1,a)≤query(A,B2,a)query(A,B1,b)≤query(A,B2,b)
而且最多只有一个取等。因此便可以把
B
1
\tt B_1
B1 判断出来了。
CODE
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
#define INF 0x3f3f3f3f
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
inline int ask(int a,int b,int c) {
cout<<"? "<<a<<" "<<b<<" "<<c<<endl;
int as; cin>>as; return as;
}
int a[MAXN],p[MAXN],ar[MAXN];
vector<int> bu[MAXN];
int main() {
srand(time(0));
int T;cin>>T;
while(T --) {
cin>>n;
for(int i = 1;i <= n;i ++) bu[i].clear(),a[i] = 0,ar[i] = i;
random_shuffle(ar + 1,ar + 1 + n);
int A = 1,B = 2,C = 3,as,flag1 = 0;
for(A = 1;A <= 11;A ++) {
for(B = A+1;B <= 12;B ++) {
for(C = B+1;C <= 13;C ++) {
if((as=ask(A,B,C)) <= ((n-4)/6)) {
flag1 = 1; break;
}
}
if(flag1) break;
}
if(flag1) break;
}
int mi = n+1,ct = 1,ct2 = 0,ma = 0;
for(int i = 1;i <= n;i ++) {
if(i != A && i != B) {
a[i] = ask(A,B,i);
if(a[i] < mi) mi = a[i],ct = 1;
else if(a[i] == mi) ct ++;
if(a[i] == 2) ct2 ++;
ma = max(ma,a[i]);
bu[a[i]].push_back(i);
}
}
int H = bu[ma][0],H2 = bu[ma-1][0];
if((int)bu[ma-1].size() > 1) {
int H3 = bu[ma-1][1];
if(ask(H,H2,A) <= ask(H,H3,A) && ask(H,H2,B) <= ask(H,H3,B)) {
H2 = H2;
}
else H2 = H3;
}
p[H] = 1; p[H2] = 2;
for(int i = 1;i <= n;i ++) {
if(i != H && i != H2) {
p[i] = 2 + ask(H,H2,i);
}
}
if(p[1] > p[2]) {
for(int i = 1;i <= n;i ++) p[i] = n-p[i]+1;
}
cout<<"!";
for(int i = 1;i <= n;i ++) cout<<" "<<p[i];
cout<<endl;
int AC; cin>>AC;
}
return 0;
}
Solution #2
非常精妙的做法,不愧是
O
n
e
I
n
D
a
r
k
\tt OneInDark
OneInDark !
主要是选择两对数来进行序列
q
\tt q
q 的确定,通过
q
\tt q
q 和
q
′
\tt q'
q′ 确定原序列。这里笔者就不展开了。原博客还是写了满大页的。
[CF1526F] Median Queries(交互 / 构造)的更多相关文章
- B - Median Pyramid Easy 构造题
B - Median Pyramid Easy Time limit : 2sec / Memory limit : 256MB Score : 400 points Problem Statemen ...
- $AT2163\ Median\ Pyramid\ Easy$ 构造
正解:构造 解题报告: 传送门$QwQ$ 考虑如果有两个相邻格子是相同数字那么它们以上这两列就都会是这列数字(显然$QwQ$? 所以考虑只要构造出第$n-1$行的中心和中心右侧($or$左侧一样的$Q ...
- Gym - 100851J: Jump(交互+构造+(大胆瞎搞)))
题意:给定长度为N的01串,现在让你猜这个串,猜的次数要不超过N+500次. 每次你猜一个串,系统会返回N/2,或N,或0.当且当有N/2个位置猜对,N个位置猜对,其他. 思路:因为信息不多,没有关联 ...
- Codeforces Round #669 (Div. 2) C. Chocolate Bunny (交互,构造)
题意:有一个长度为\(n\)的隐藏序列,你最多可以询问\(2n\)次,每次可以询问\(i\)和\(j\)位置上\(p[i]\ mod\ p[j]\)的结果,询问的格式是\(?\ x\ y\),如果已经 ...
- Codeforces Round #356 (Div. 2)
A. Bear and Five Cards time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- Kafka connect快速构建数据ETL通道
摘要: 作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 业余时间调研了一下Kafka connect的配置和使用,记录一些自己的理解和心得,欢迎 ...
- Educational Codeforces Round 65 (Rated for Div. 2) B. Lost Numbers
链接:https://codeforces.com/contest/1167/problem/B 题意: This is an interactive problem. Remember to flu ...
- OrmLite使用小结(一)
在使用OrmLite过程中,遇到了不少问题.鉴于中文文档比較少,看英文文档又不知道怎样看起.仅仅能遇到问题查找解决方法并整理出来,如有错误,希望能指正! ** 1.模糊条件查询 ** 使用条件查询时. ...
- 【Python】使用cmd模块构造一个带有后台线程的交互命令行界面
最近写一些测试工具,实在懒得搞GUI,然后意识到python有一个自带模块叫cmd,用了用发现简直是救星. 1. 基本用法 cmd模块很容易学到,基本的用法比较简单,继承模块下的Cmd类,添加需要的功 ...
随机推荐
- Java JavaMail通过SMPT发送邮件
概述 本讲讲述如何使用JavaMail工具包,通过SMPT协议,在Java代码中发送邮件. 一.JavaMail简介 JavaMail API提供了一个独立于平台且与协议无关的框架来构建邮件和消息传递 ...
- 安装@parcel/transformer-image注意的问题
安装前配置 npm config get cache 键入以上命令即可找到npm缓存路径,然后找到路径下的_libvips文件夹. 一般需要以下两个文件,这里以win环境为例.把文件放到_libvip ...
- 引入gitlab仓库代码到npm包的教程
背景介绍 随着人类地发展,社会地进步,计算机技术地更新迭代,每一片码海里都有它宝贵的财富,每一座码山里都有着各自的秘密.怎么守住财富,隐藏一些秘密,成了一些开发人员所关心的事情. 需求分析 简单地说, ...
- SAP 实例 6 HTML input
REPORT demo_html_input. CLASS demo DEFINITION. PUBLIC SECTION. CLASS-METHODS main. PRIVATE SECTION. ...
- NHibernte 4.0.3版本中,使用Queryover().Where().OrderBy().Skip().Take()方法分页获取数据失败
问题代码如下: var result=repository.QueryOver<modal>() .Where(p=>p.Code==Code) .OrderBy(p=>p.I ...
- 获取请求体数据 POST
POST获取请求体 请求体中封装了 POST请求的请求参数 获取流对象 再从流对象中那数据 一种字节流 一种字符流 BufferedReader getReader()获取字符输入流 只能操作字符 S ...
- Python简单实现自动评论、自动点赞、自动关注脚本
一些哔哔: 今天的这个脚本,是一个别人发的外包,交互界面的代码就不在这里说了,但是可以分享下自动评论.自动点赞.自动关注.采集评论和视频的数据是如何实现的 开发环境 python 3.8 运行代码py ...
- 不花钱~Python制作视频解析免费追剧神器
同学们在闲暇之余是否喜欢看电影或者电视剧呢? 今天带领大家使用python制作能免费追剧的桌面软件.还在等什么?发车了! 效果我就不再这里演示了https://jq.qq.com/?_wv=1027& ...
- 研发效能|Kubernetes核心技术剖析和DevOps落地经验
本文主要介绍Kubernetes 的核心组件.架构.服务编排,以及在集群规模.网络&隔离.SideCar.高可用上的一些使用建议,尤其是在CICD中落地,什么是 GitOps. 通过此文可彻底 ...
- Netty源码解读(三)-NioEventLoop
先看看EventLoop类图 我们在Netty第二篇文章中的代码中,看到有多次用到eventLoop.execute()方法,这个方法就是EventLoop开启线程执行任务的关键,跟踪进去看看 // ...