喵喵交互题。
题目链接。
题意
现在有一个长度为  的排列 (下标从 
开始),你需要在若干次询问内问出它。
每一次询问需要给出一个排列 ,以及两个数字 ,交互库将会返回  中, 是否在同一个置换环。
,询问次数限制为  次。
题解
我还是第一次见到函数式交互题还需要我写主函数的。
感觉这题人类想不出来。
设 ,考虑能不能找到一个合适的 ,让  中恰好有一个置换环。
假设此时我们知道  中 
不在一个置换环内,我们是否可以通过改变  来让这两个环合并呢。

我们直接让原来指向  的指向
,原来指向  的指向  就好了。
这样我们就可以在  次操作以内让
 内只有一个置换环。
考虑我们能不能知道,此时 
长成什么样子。
考虑找两个点 ,如果我们让原来指向  的指向 ,原来指向  的指向 ,会发生什么。

可以发现,两个点中,更前面的一个,分裂出了一个环,并且这个环不包含
。
也就是说,我们可以使用一次询问,知道两个点谁在前面。
也就是说我们可以用 
次询问知道  长什么样子。
因为 ,那么 ,我们就得到了 。
询问次数是 。
代码
| 12
 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;
 }
 
 
 
 
 
 
 
 |