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

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

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