0%

[XXXI POI] Permutacje

喵喵交互题。

题目链接

题意

现在有一个长度为 的排列 (下标从 开始),你需要在若干次询问内问出它。

每一次询问需要给出一个排列 ,以及两个数字 ,交互库将会返回 中, 是否在同一个置换环。

,询问次数限制为 次。

题解

我还是第一次见到函数式交互题还需要我写主函数的。

感觉这题人类想不出来。

,考虑能不能找到一个合适的 ,让 中恰好有一个置换环。

假设此时我们知道 不在一个置换环内,我们是否可以通过改变 来让这两个环合并呢。

我们直接让原来指向 的指向 ,原来指向 的指向 就好了。

这样我们就可以在 次操作以内让 内只有一个置换环。

考虑我们能不能知道,此时 长成什么样子。

考虑找两个点 ,如果我们让原来指向 的指向 ,原来指向 的指向 ,会发生什么。

可以发现,两个点中,更前面的一个,分裂出了一个环,并且这个环不包含

也就是说,我们可以使用一次询问,知道两个点谁在前面。

也就是说我们可以用 次询问知道 长什么样子。

因为 ,那么 ,我们就得到了

询问次数是

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<bits/stdc++.h>
#include "perlib.h"
using namespace std;
template<typename A>
using vc=vector<A>;

int id[505];
int wh[505];
int q[505];
int a[505];
int n;
inline bool query(int a,int b)
{
vc<int>qq;
for(int i=0;i<n;i++) qq.push_back(q[i]);
return zapytaj(qq,a,b);
}
inline void rebuild()
{
for(int i=0;i<n;i++) wh[q[i]]=i;
}
void cdq(int l,int r)
{
if(l>=r) return ;
int mid=(l+r)>>1;
cdq(l,mid),cdq(mid+1,r);
inplace_merge(id+l,id+mid+1,id+r+1,[](int i,int j)
{
int w1=wh[i],w2=wh[j];
q[w1]=j,q[w2]=i;
bool res=query(0,i);
q[w1]=i,q[w2]=j;
return !res;
});
}
int main()
{
n=daj_n();
for(int i=0;i<n;i++) id[i]=q[i]=wh[i]=i;
for(int i=1;i<n;i++) if(!query(0,i))
{
int w1=wh[0],w2=wh[i];
q[w1]=i,q[w2]=0;rebuild();
}

cdq(1,n-1);
for(int i=0;i<n;i++) a[id[i]]=id[i+1];

vc<int>ans;
for(int i=0;i<n;i++) ans.push_back(wh[a[i]]);
odpowiedz(ans);
return 0;
}
/*
g++ T1.cpp perlib.cpp -o T1 -std=c++14 -Wall
T1
5 100000
3 2 1 0 4
*/

Related Issues not found

Please contact @shijiuwan to initialize the comment