再次无聊2023.10.19
0x00. IO交互题——快速入门
个人认为对构造题有帮助,毕竟 \(\text{IO}\) 交互和构造基本是一个东西。
CF679A Bear and Prime 100
题意:一个数 \(x\in[2,100]\),你可以进行不超过 \(20\) 次询问,每次询问一个 \([2,100]\) 的数,交互库给出其是否为 \(x\) 的约数,试判断 \(x\) 是否为合数。
不难想到利用质因数询问。
一个 \([2,100]\) 合数,至少有一个 \(\le 10\) 的质因数,所以先询问 \(2,3,5,7\)。
问出一个质因数后,我们不需要再问 \(>50\) 的质因数。
然后依次询问每个质因数即可,注意 \(4,9,25,49\) 的情况。
CF1167B Lost Numbers
题意:一个由 \(4,8,15,16,23,42\) 组成的排列 \(P\),你可以进行不超过 \(4\) 次询问,每次可以问两个数 \(P_i,P_j\) 的乘积,找出这个排列。
不难发现任意两个不同数的乘积不同,于是一个询问即可得出这两个数分别是多少,但我们无法确定顺序。
考虑到求出 \(P_{1...5}\) 后即可求出 \(P_6\),先去掉 \(P_6\)。
不难想到询问 \((1,2),(2,3),(3,4),(4,5)\),即可。
CF1407C Chocolate Bunny
题意:一个 \(1...n\) 的排列 \(a\),每次可以询问 \(a_x\bmod a_y\) 的值,最多询问 \(2n\) 次,找出这个排列。
对于 \((x,y)\) ,不难发现 \(a_x\bmod a_y\) 和 \(a_y\bmod a_x\) 中总有一个数等于 \(a_x\) 和 \(a_y\) 中的一个数。进一步的,\(\max(a_x\bmod a_y,a_y\bmod a_x)=\min(a_x,a_y)\)。
于是两次询问 \((x,y),(y,x)\) 即可确定 \(\min(a_x,a_y)\)。
先确定 \(\min(a_1,a_2)\),然后将未确定的数保留,继续与 \(a_3\) 进行询问。以此类推,即可得出 \(n-1\) 个数的值,剩下一个数就能立马确定。
CF1451E2 Bitwise Queries
题意:\(n\) 是一个 \(2\) 的幂(存在 \(m\) 满足 \(n=2^m\)),有一个序列(非排列)\(a_{0...n-1}\),你每次可以询问其中两个数 \(\operatorname{and}/\operatorname{or}/\operatorname{xor}\) 后的结果,至多询问 \(n+1\) 次。请求出整个序列。
与、或的可用信息较少,考虑用异或来获取有效信息。
询问出 \(a_0\) 与 \(a_{1...n-1}\) 的异或结果,设为 \(b_{1...n-1}\)。
我们现在只需要求出 \(a_0\) 即可求出整个序列,考虑找两个二进制下无交集的两个 \(b_x,b_y\),询问 \(a_0\) 分别与 \(a_x,a_y\) 的 \(\operatorname{and}\) 的结果,然后就能容易确定 \(a_0\)。
如果不存在这样的两个数,那么一定就会存在两个 \(b_x,b_y\) 满足 \(b_x=b_y\)。我们询问 \(b_x\operatorname{and} b_y\),一样可以得出 \(a_0\)。
CF1114E Arithmetic Progression
题意:一个打乱的等差序列,你可以每次询问是否存在一个 \(>x\) 的数,或者询问 \(a_x\)。在 至多 \(60\) 次询问 内求出原等差数列的首项和公差。\(1\le n\le 10^6,\space 1\le a_i\le 10^9\)
先二分出末项。
然后考虑随机化,随机选择 \(a\) 中一些数,求两两差值 \(\text{gcd}\) 即可。
0x01. 非常无聊
CF1552G A Serious Referee
题意:有 \(n\) 个数 \(a_{1...n}\),以及 \(m\) 次操作。每次给出若干个位置 \(j_1,j_2,...,j_q\),表示把 \(a_{j_1},a_{j_2},...,a_{j_q}\) 升序排序。判断是否对于所有可能的序列,最终都能形成升序序列。
\(1\le n\le 40,\space 1\le k\le 10\)
套用 经典套路,所有序列都能排序的充要条件是对于所有 \(01\) 序列都能排序。
一种暴力是直接枚举 \(0...2^n-1\),时间复杂度 \(O(2^nk)\)。
似乎不能折半,注意到 \(k\) 比 \(n\) 还小很多,尝试挖性质。
每次排序操作,会调用一些新的下标,我们只关注这些新下标对应的有多少个 \(0/1\)。
于是,我们只需要枚举新下标对应 \(0/1\) 个数。
一些位置上的操作可以用二进制数代替,优化时间。科普:__built_popcount/__built_popcountll
帮助计算二进制下 \(1\) 的个数。
最坏情况每次操作 \(\frac nk\) 个,此时时间复杂度 \(O((\frac nk)^k)\)。
CF1876D Lexichromatography
题意:一个序列 \(a_{1...n}\),给每个位置染黑/白色。需要满足,对于每个子段和每个 \(k\),其 \(a_i=k\) 的位置挖出来,黑色位置数量与白色位置数量差的绝对值 \(\le 1\);同时,黑色位置上的数连出来的子序列字典序 严格大于 白色。求方案数,模 \(998244353\)。
若不考虑字典序限制,对于一种方案,每个位置颜色取反,可以得到另一种类似的方案。
考虑字典序限制,一对类似的方案,至多有一个方案合法。
但是可能一对类似的方案,两个都不合法,此时两个子序列的字典序是相同的,我们只需要算出字典序相同的方案,然后用总方案减去即可。
设总方案为 \(\text{ALL}\),字典序相同的方案为 \(\text{R}\),答案为
先考虑计算总方案数,显然,两两值域是独立的。
差绝对值 \(\le 1\) 的限制相当于不存在 值域独立意义下 两个相邻的位置颜色相同。
发现对于每个值,贡献为 \(2\),容易计算。
然后考虑计算字典序相同的方案数。
考虑一位一位扫 \(a\) 序列,设 \(vis[x]\) 表示 \(x\) 这个值是否已加入一个子序列,而未加入另一个子序列。
当扫到一个 \(a_i\):
- 若 \(vis[a_i]=1\)
我们一定不能继续往相同的子序列加入 \(a_i\),这样会导致颜色相同。
维护一个队列,表示长度较大的子序列多出来的数,然后判断队首是否为 \(a_i\)。
- 若 \(vis[a_i]=0\)
直接加入一个子序列。注意加入不同子序列有贡献,发现这个贡献不是简单的 \(2\)。
比如一开始先加入 \(1,2\),贡献为 \(2\)。
之后某一时刻加入 \(3,2\),我们发现 \(2\) 加入的子序列与之前加入的一定是相同的。
然后可以把同一时刻队列内的数用并查集合并,最后若分成了 \(w\) 个集合,贡献为 \(2^w\)。
时间复杂度 \(O(n)\)。