题面

这是一道交互题。

有一个未知的长度为

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(交互 / 构造)的更多相关文章

  1. B - Median Pyramid Easy 构造题

    B - Median Pyramid Easy Time limit : 2sec / Memory limit : 256MB Score : 400 points Problem Statemen ...

  2. $AT2163\ Median\ Pyramid\ Easy$ 构造

    正解:构造 解题报告: 传送门$QwQ$ 考虑如果有两个相邻格子是相同数字那么它们以上这两列就都会是这列数字(显然$QwQ$? 所以考虑只要构造出第$n-1$行的中心和中心右侧($or$左侧一样的$Q ...

  3. Gym - 100851J: Jump(交互+构造+(大胆瞎搞)))

    题意:给定长度为N的01串,现在让你猜这个串,猜的次数要不超过N+500次. 每次你猜一个串,系统会返回N/2,或N,或0.当且当有N/2个位置猜对,N个位置猜对,其他. 思路:因为信息不多,没有关联 ...

  4. Codeforces Round #669 (Div. 2) C. Chocolate Bunny (交互,构造)

    题意:有一个长度为\(n\)的隐藏序列,你最多可以询问\(2n\)次,每次可以询问\(i\)和\(j\)位置上\(p[i]\ mod\ p[j]\)的结果,询问的格式是\(?\ x\ y\),如果已经 ...

  5. Codeforces Round #356 (Div. 2)

    A. Bear and Five Cards time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  6. Kafka connect快速构建数据ETL通道

    摘要: 作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 业余时间调研了一下Kafka connect的配置和使用,记录一些自己的理解和心得,欢迎 ...

  7. 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 ...

  8. OrmLite使用小结(一)

    在使用OrmLite过程中,遇到了不少问题.鉴于中文文档比較少,看英文文档又不知道怎样看起.仅仅能遇到问题查找解决方法并整理出来,如有错误,希望能指正! ** 1.模糊条件查询 ** 使用条件查询时. ...

  9. 【Python】使用cmd模块构造一个带有后台线程的交互命令行界面

    最近写一些测试工具,实在懒得搞GUI,然后意识到python有一个自带模块叫cmd,用了用发现简直是救星. 1. 基本用法 cmd模块很容易学到,基本的用法比较简单,继承模块下的Cmd类,添加需要的功 ...

随机推荐

  1. node.js环境安装及环境变量

    1.nodejs官网下载对应系统的安装包 2.除了你想自定义安装的路径其他一切一直点next往下走 3.打开cmd命令窗口输入node -v,看到v.xx.xx代表node已经装好 node -v 4 ...

  2. VMware虚拟机基于contos 7 搭建lnmp环境全过程

    这个环境也整了几次了,由于本人比较懒,没有记住.找资料很麻烦,就自己动手咯 1.下载VMware虚拟机   (有注册码)     地址:http://www.zdfans.com/5928.html ...

  3. 如何正确理解古典概率中的条件概率 《考研概率论学习之我见》 -by zobol

    "B事件发生的条件下,A事件发生的概率"? "在A集合内有多少B的样本点"? "在B约束条件下,A发生的概率变化为?" "B事件中 ...

  4. 我给航母做3D还原:这三处细节,太震撼了…

    前两天,我国第三艘航母正式下水,受到国际舆论高度关注.国产福建舰火出了圈,"航母"从军事专业领域,也火到了普通人的视野中. 图源网络 人们一边感叹我国实力强劲,一边对"航 ...

  5. HTML,CSS,JS,DOM,jQuery

    HTML 超链接访问顺序 a:link-->a:visited-->a:hover-->a:active.(有顺序) link:表示从未访问过的链接的样式 visited:表示已经访 ...

  6. SAP Web Dynpro-版本管理

    您可以使用版本管理来管理对象的旧版本,比较版本,也可以重置它们. 在版本管理中,您可以存储ABAP开发对象的不同版本. 在ABAP工作台中,您可以比较不同版本的- 视图 视窗 控制器 您也可以存储对象 ...

  7. Git代码提交报错 (Your branch is up to date with 'origin/master)

    一.前言 今天码云上提交自己本地的一个SpringBoot+Vue的小项目,由于前端代码提交第一次时候提交码云上文件夹下为空,于是自己将本地代码复制到码云拉取下来代码文件夹下,然而git add . ...

  8. idea启动java Maven项目,出现" java: 程序包xxxx不存在"

    解决办法如下:将idea的构建和运行托管到maven下面

  9. SQLZOO练习二--SELECT from Nobel Tutorial

    We continue practicing simple SQL queries on a single table. This tutorial is concerned with a table ...

  10. HTTPS 如何保证数据传输安全

    引言 为什么把这个作为选题. 大概也是2年前,我的同事,在面试某宇宙大厂遇到的问题与我一起探讨.这个时候我发现,虽然TLS(https)这个东西大部分时候可能不会被直接用到,但很容易被作为考察的目标范 ...