部分交互题做题记录

放一些感觉有意思的交互题(

http://codeforces.com/problemset/problem/1438/F

有一棵高度为 \(h\) 的完美二叉树 \((n=2^h-1)\) ,每次你可以询问三个互不相等的正整数 \(u,v,w\) ,交互库会返回以 \(w\) 为根时 \(u,v\)\(LCA\) ,询问至多 \(n+420\) 次,最后要返回根的编号。

\(3\le h\le 18\)

神奇的乱搞题,个人不太喜欢。

把交互库返回的东西转换一下,可以看作找到一个点 \(x\) 使得 \(dis(x,u)+dis(x,v)+dis(x,w)\) 最小。

然后可以发现,如果 \(u,v,w\) 随机,找到的 \(x\) 为根的左右儿子的概率比为其他点的概率大的多, \(h\) 越大就越明显。

然后随机问 \(420\) 次,将返回的答案中出现最多的两个看作根的左右儿子,然后枚举哪个点为根看返回的答案是否是该点便可。

虽然理论上很大概率是对的,但是不知为何我的代码找到的两个点总是有一个为根,如果上面的方法过不了不妨加个有一个为根的判断。

http://codeforces.com/problemset/problem/1444/E

给你一个 \(n\) 个节点的树,存在一个特殊节点 \(S\) ,每次你可以询问一条边 \((u,v)\) ,交互库会返回 \(u,v\) 中离 \(S\) 近的那一个, \(S\) 是动态构造,要你在最少的询问次数下得出节点 \(S\)

\(n\le 100\)

略微翻译一下题意,发现只是套了个交互的皮,实际上是要你搞一个边分树使得最大深度最小,然后我 navie 地写了个边分治爆蛋了。

有一个我想不到的好玩的转换,假设已知边分树,那么可以对边打上对应深度的值,根据边分树的性质,显然有:

  • 任意两个值相等的边之间的路径一定存在一条边的值小于这个两个边的值。

然后对于一个节点 \(u\) ,考虑他的子树都符合上面的条件,有一个值的集合 \(S\) 里的值有可能会导致不满足上面的情况(指找到不另外一个值相等的边且到 \(u\) 的路径上的值都大于改值)。

考虑将这个集合压缩成二进制数,每次合并到父亲的问题就转变为了:

  • 给定 \(\deg (x)\) 个数 \(c_i\) ,你需要确定一组 \(b_i\) 满足 \(b_i>c_i\) 且满足 \(b_1~\&~b_2...~\& ~b_{\deg(x)}=0\) ,然后令 \(b_x=b_1|b_2|b_3...|b_{\deg(x)}\) ,我们需要最小化 \(b_x\)

这个东西可以贪心,压缩可以考虑 __int128 或者 bitset

复杂度 \(\mathcal{O(n^3poly(n))}\)

https://atcoder.jp/contests/arc070/tasks/arc070_d

\(n=a+b\) 个人,你知道有 \(a\) 个诚实的人和 \(b\) 个不诚实的人,每次询问你可以向第 \(x\) 个人询问第 \(y\) 个人是否诚实,诚实的人一定说真话,不诚实的人可能说真话也可能说假话,最多询问 \(2n\) 次,要求得出每个人的种类,不可能得出则输出 Impossible

\(1\le a,b\le 2000\)

大力分类讨论便可。

首先,当 \(a\le b\) 时,要输出 Impossible

分类讨论向第 \(x\) 个人和第 \(y\) 个人分别问对方是否诚实的情况:

  1. 两个都是 \(Yes\) ,那就意味着这两个人是一类人。

  2. 一个 \(Yes\) 和一个 \(No\) ,那么被说成 \(No\) 的人一定不诚实,另一个人未知。

  3. 两个都是 \(No\) ,那么至少有一个人是不诚实的。

目前我们有 \(a>b\) 的条件,如果在情况二时将不诚实的删去,将情况三的两个人都删去,那么依然可以保证 \(a>b\) ,考虑递归来缩小数据。

到了最后一定可以得到一个诚实的人,那么便可向他询问那些不清楚类别的人,如情况三删去的两人。

分析一波可以发现询问次数的上界是 \(2n\)

https://codeforces.com/problemset/problem/1466/I

\(n\) 个数 \(\{a\}\)\(a_i<2^b\) ,每次你可以询问 \(a_i\)\(x\) 的大小关系,请在 \(3(n+b)\) 次询问中得到最大值。

\(n\le 1000 , b\le 20\)

咕咕咕。

http://codeforces.com/problemset/problem/1514/E

有一张 \(n\) (\(4≤n≤100\)) 个点的竞赛图,你可以进行以下两种询问:

  • 询问 \(a\)\(b\) 之间的边的方向。这种询问最多进行 \(9n\) 次。

  • 询问 \(x\) 是否向 \(s1,s2,…,sk\) 当中的至少一个点连边。这种询问最多进行 \(2n\) 次。

最终,你需要对所有 \(1≤a,b≤n\) 求出是否存在 \(a\)\(b\) 的路径。

先找出一条包含 $n$ 个点的路径,考虑对于现有的路径 $p_1,p_2,...,p_{x-1}$ ,插入第 $x$ 号点,需要找到一个 $y$ ,满足 $p_y->x$ 且 $x->p_{y+1}$ 。

由于如果存在 \(p_l->x\)\(x->p_r\) ,一定存在一个 \(y\in [l,r)\) 满足条件,可以二分。

找到路径后,从后往前缩成许多个强连通块即可。

posted @ 2021-03-12 21:43  Dabuliuzp  阅读(69)  评论(0编辑  收藏  举报
/* */ 返回顶端