题面

这是一道交互题。

有一个未知的长度为

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. 『忘了再学』Shell基础 — 32、Shell中test测试命令详解

    目录 1.test测试命令 (1)test命令介绍 (2)test命令使用方式 (3)示例 2.按照文件类型进行判断 3.按照文件权限进行判断 4.两个文件之间进行比较 5.两个整数之间比较 6.字符 ...

  2. nifi从入门到实战(保姆级教程)——环境篇

    背景: 公司领导决定将各种基础数据的导入从代码中分离出来,用Apache Nifi替换.使开发者们更关注在业务上,而不用关心基础的由来. Apache Nifi对于整个团队都是一个全新的工具,之前大家 ...

  3. mysql密码忘记了重置方法

    #先把mysql停止 service mysqld stop #安全模式进入mysql,并且跳过授权表 mysqld_safe --skip-grant-tables & #如果上面这个命令报 ...

  4. SQL Server数据库 备份A库,然后删除A库,再还原A库,此时数据库一直显示“正在还原”的解决方法

    SQL Server数据库 备份A库,然后删除A库,再还原A库,此时数据库一直显示"正在还原"的解决方法: A库一直显示"正在还原". 在这种状态下,由于未提交 ...

  5. Day02 HTML语法

    有两种类型的标签 双标记<标记名>内容</标记名> 单标记<标记名/> 属性: 对标签的描述--属性,由属性名和属性值组成 <标记名 属性名 = " ...

  6. PMP 考试常见工具与技术点总结

    转载请注明出处: 网络图:项目进度活动之间的逻辑关系,用来推算关键路径,最大浮动时间等: 横道图(甘特图):以图示的方式,通过活动列表和时间刻度,来展示项目获得那个顺序和持续时间 责任分配矩阵:每件事 ...

  7. go 编程规范

    如果没有编程规范会有什么问题? 哪些地方可以需要指定规范? 非编码类规范:编码规范 非编码规范 开源规范 http://www.ruanyifeng.com/blog/2011/05/how_to_c ...

  8. while循环--和do-while循环

    对于循环语句来说他会有一个回上去的箭头,这个回上去的箭头就形成了一个重复做的事情,那种重复做的事情我们就叫做循环 while循环 ~如果我们把while翻译作"当",那么一个whi ...

  9. 常用类-Instant、DateTimeFormatter类的使用

    一.Instant 我们所处的时间点是在东八区,Java中Instant所计算出来的时间是按本初子午线的时间来算的,与我们的时间相差8个小时,也就是说当我的北京时间是上午九点时,本初子午线的时间是凌晨 ...

  10. Solution -「校内题」Xorequ

    0x00 前置芝士 数位dp考试里出现的小神题?? 显然考场会选择打表找规律. 数位dp + 矩阵快速幂 0x01 题目描述 给定正整数 \(n\),现有如下方程 \(x \bigoplus 3x = ...