【学习笔记】构造题

280 篇文章 1 订阅
89 篇文章 0 订阅

有用的方法:

  • 看看方案有什么性质。
  • 找找答案上界——很有可能取得到。
  • 归纳法构造(或者叫递归)。
  • 大胆猜想。做法毕竟是人类想到的,不可能过分离谱。

题目描述

一个 2 n − 1 2^n-1 2n1 个点的完全图,你需要划分出尽量多的边不相交的三元环。 n ≤ 10 n\le 10 n10

题解

考虑答案的上界,所有边都被用到一次。即 ( 2 n − 1 ) ( 2 n − 2 ) 2 × 1 3 \frac{(2^n-1)(2^n-2)}{2}\times\frac{1}{3} 2(2n1)(2n2)×31

容易发现是整数(因为 2 n 2^n 2n 不是 3 3 3 的倍数,那么减一、减二必然有一个是)。大胆猜测这是可以取到的。那么对于每一条边 ⟨ x , y ⟩ \lang x,y\rang x,y 都要找到一个三角形才行。怎么找呢?设其为 f ( x , y ) f(x,y) f(x,y) ,那么显然还要有 f [ f ( x , y ) , x ] = y f[f(x,y),x]=y f[f(x,y),x]=y

可以猜想 f ( x , y ) , x , y f(x,y),x,y f(x,y),x,y 满足一个轮换式的等式。然而它是什么呢?结合 2 n − 1 2^n-1 2n1 ,让人联想到 异或,恰好有且仅有一个解。(记住,编号从 1 1 1 开始。)

所以 f ( x , y ) ⊕ x ⊕ y = 0 f(x,y)\oplus x\oplus y=0 f(x,y)xy=0 就是我们需要的等式。而且 f ( x , y ) ≠ x f(x,y)\ne x f(x,y)=x 也成立。

题目描述

一个 2 n 2n 2n 个点的完全图,把这些边分成 2 n − 1 2n-1 2n1 组(每组 n n n 条边),使得每一组内的两条边不共点。 n ≤ 1 0 3 n\le 10^3 n103

思路

自己模拟一下,画一个正多边形,容易想到一种 “平行线” 思路。但是这个方法就很迷惑了:去掉 2 n 2n 2n 这个点。

形式化地,画平行线就是 x + y ≡ k ( m o d 2 n − 1 ) x+y\equiv k\pmod{2n-1} x+yk(mod2n1) ,这里 k k k 为定值。编号从 0 0 0 开始。

容易发现每组都会恰好剩下一个 k 2 \frac{k}{2} 2k ,因为 2 2 2 在模 2 n − 1 2n-1 2n1 意义下的逆元存在。然后将一开始去掉的 2 n 2n 2n 与它连上就行。不过这是怎么想到的呢?

题目描述

n n n 个点完全图,划分成尽量多的边不相交的生成树。 n ≤ 1 0 3 n\le 10^3 n103

思路

上界为边数除以 n − 1 n-1 n1 ⌊ n 2 ⌋ \left\lfloor\frac{n}{2}\right\rfloor 2n

归纳法。假设 n = 2 k n=2k n=2k 是可行的,考虑让 n = 2 k + 1 n=2k+1 n=2k+1 n = 2 k + 2 n=2k+2 n=2k+2 均成立。

n = 2 k n=2k n=2k 的情形下,所有边都被用到了,所以每个点都存在于目前的 k k k 棵生成树中。随便选 k k k 个不同的点(代表 k k k 个生成树)连上 2 k + 1 2k+1 2k+1 就证明了 n = 2 k + 1 n=2k+1 n=2k+1 的情形。

n = 2 k + 2 n=2k+2 n=2k+2 ,假设选出的 k k k 个点是 A A A 集合,剩下 k k k 个点是 B B B 集合。用类似的方法, A A A 都向 2 k + 1 2k+1 2k+1 连、 B B B 2 k + 2 2k+2 2k+2 连。然后得造一棵新的生成树。 A A A 2 k + 2 2k+2 2k+2 连、 B B B 2 k + 1 2k+1 2k+1 连、 ⟨ 2 k + 2 , 2 k + 1 ⟩ \lang 2k+2,2k+1\rang 2k+2,2k+1 就足够了。

题目描述

平面上 n n n 蓝点,保证任意三点不共线。加入最少的红点,使得任意三个蓝点构成的三角形内部都至少有一个红点。红点必须在内部,而非边上。 n ≤ 1 0 2 n\le 10^2 n102

思路

连答案的下界都非常难找到……

做凸包,进行三角剖分。设进行了 p p p 次凸包,点数分别为 l 1 , l 2 , … , l p l_1,l_2,\dots,l_p l1,l2,,lp ,那么三角剖分数量为

( l p − 2 ) + ∑ i = 1 p − 1 ( l i + l i + 1 ) (l_p-2)+\sum_{i=1}^{p-1}(l_i+l_{i+1}) (lp2)+i=1p1(li+li+1)

由于这些三角形两两无交集,所以是答案下界。化简易知其为 2 n − 2 − l 1 2n-2-l_1 2n2l1

p . s . p.s. p.s. 比较特殊的情况是 l p = 1 l_p=1 lp=1 。此时,倒数第二层,三角剖分有 l p − 1 l_{p-1} lp1 个,而最内层只有一个点。巧妙的是,计算出来恰好相等。

然后我们用一个奇怪的方法去构造:随机一个长度足够小的、不与边平行的向量 p ⃗ \vec{p} p ,然后把每个点 + p ⃗ +\vec{p} +p − p ⃗ -\vec{p} p 的位置放上两个红点。为何它一定可行呢?因为三角形内角和是 π \pi π ,而这两个红点恰好使得任意一个 18 0 ∘ 180^{\circ} 180 角内都有红点。

好像是 2 n 2n 2n 啊……然而,对于最外层凸包上的蓝点,只需要保留凸包内的那个红点。更甚一步,有两个蓝点对应的红点是全都在凸包外(就是旋转卡壳的时候找到的那两个)。所以恰好为 2 n − 2 − l 1 2n-2-l_1 2n2l1你这都能想到?

题目描述

一个 n × n n\times n n×n 的方格表,每个格子里有一个小写英文字母。你每次操作可以把某一行循环移位若干格,或者把某一列循环移位若干格。

你需要在 1 0 4 10^4 104 次操作内,最大化 k e y key key 的数量。某一行的连续三个格子恰好分别为 k , e , y k,e,y k,e,y 时我们认为 k e y key key 出现了一次。 n ≤ 40 n\le 40 n40

思路

直接把 k , e , y k,e,y k,e,y 拿出来,使其尽量多的形成 k e y key key 就是了。

大胆猜想 答案可以是每一行都形如 k e y k e y k e y ⋯ keykeykey\cdots keykeykey 的形式。那么考虑一列一列地填字符。

玩过 魔方 的童鞋肯定知道怎么做:把某一行顶出来,需要的字符利用列的移位,装填到那一行上,然后把那一行塞回去。填一个字符只需要最多 5 5 5 次(如果想要的字符原本就在那一列上)。

只有一种问题,就是 n n n 是三的倍数,并且 k , e , y k,e,y k,e,y 的数量恰好使得我们需要用到最后一列。这个时候,最后一列没有操作的余地了,所以可能 没法和倒数第二列对齐。我们得解决这个问题。

如果第 n − 1 n-1 n1 列填满了,那么最后一列怎么填无所谓了。我们只讨论第 n − 1 n-1 n1 列没填满,也就是第 n − 1 n-1 n1 列的第 n n n 行是无用字符的情况。这玩意儿就会成为我们的中转点。

现在我们要实现,将最后一列的第 a a a 行的有用字母放到第 b b b 行,代替原本在那里的无用字符。我们首先将第 a a a 行移动到第 n n n 行,然后把第 n n n 行向右推一步。这时候,第 a a a 行的这个有用字符被储存在了第一列;原本在倒数第二列的,是个无用字符,即使进入了最后一列,也并不影响。

然后把第 b b b 行移动到最后一行,把第 n n n 行左推一步,就把有用字符给镶嵌了进去。然后我们就可以继续我们的操作了。可以看到,我们用 4 4 4 次操作就杀死了比赛!

往大估计一些,操作次数 5 n 2 ≤ 8 × 1 0 3 5n^2\le 8\times 10^3 5n28×103 ,足以完成任务。

题目描述

给定一个长度为 n 2 + n n^2+n n2+n 的排列。你需要从中选出一个长度为 2 n 2n 2n 的子序列,使得其中第 2 k 2k 2k 大的、第 2 k + 1 2k+1 2k+1 大的,在该子序列中的位置是相邻的。 n ≤ 1 0 3 n\le 10^3 n103

思路

大胆猜想 每次可以直接选出第 2 k 2k 2k 大的、第 2 k + 1 2k+1 2k+1 大的,并且 k k k 直接从 1 1 1 取到 n n n

假如我选了最小和次小的两个,有这两个问题会出现:

  • 比次小值更小的,都不能再选了。
  • 在最小和次小之间的,都不能再选了。

由于我们一定会得到递归子问题,所以我们不在乎留下哪些(正如目前我们面对的原序列,它就是不确定的),我们 只需要让留下的值最多

如果只看第一条,好像直接选全局次小最好。然而它可能让第二条直接崩溃……所以我们调整一下,我们先看第二条带来的最坏影响。设次小值为第 p p p 小,其与第 p − 1 p-1 p1 小的差距是 k k k ,那么第 p − 1 p-1 p1 p − 2 p-2 p2 需要为 k + 1 k+1 k+1(否则选次小值为第 p − 1 p-1 p1 小更优),然后是 k + 2 k+2 k+2 ,一直到 k + p − 2 k+p-2 k+p2 。故必须满足

( 2 k + p − 2 ) ( p − 1 ) 2 ≤ n 2 + n \frac{(2k+p-2)(p-1)}{2}\le n^2+n 2(2k+p2)(p1)n2+n

此时,我们会 “死掉” k + p − 1 k+p-1 k+p1 个兄弟。要让它最大,就要让 2 k + 2 p 2k+2p 2k+2p 最大,就要让 ( 2 k + p − 2 ) + ( p − 1 ) (2k+p-2)+(p-1) (2k+p2)+(p1) 最大,就要让 2 k + p − 2 = p − 1 = 2 n 2 + 2 n 2k+p-2=p-1=\sqrt{2n^2+2n} 2k+p2=p1=2n2+2n

此时 k + p − 1 = 2 n 2 + 2 n + 1 2 k+p-1=\sqrt{2n^2+2n}+\frac{1}{2} k+p1=2n2+2n +21 是个无理数,肯定取不到。我们估算一下, 2 n 2 + 2 n ≤ 2 n 2 + 2 n + 1 2 = 2 ( n + 1 2 ) \sqrt{2n^2+2n}\le\sqrt{2n^2+2n+\frac{1}{2}}=\sqrt{2}\left(n+\frac{1}{2}\right) 2n2+2n 2n2+2n+21 =2 (n+21)

毫无疑问, k + p − 1 k+p-1 k+p1 应该是比 2 n 2n 2n 小很多。那么剩余元素不少于 n ( n − 1 ) n(n-1) n(n1) 。所以递归即可。

补充:如果直接从第二条入手,并且脑瓜子转的嗡嗡快,你会想到直接把序列划分成 n n n 段,然后取 次大值最小的 那一组的最小的两个就行。并且,你会发现,这个方法时间复杂度低很多……

题目描述

给定一个 2 n × m 2n\times m 2n×m 的格点图,其中有一半的格点是蓝色,另一半是红色。保证左上角为红色,右下角为蓝色。对于任意两个同色格点,它们之间会连出一个向量,你可以规定这个向量的方向,使得所有向量的和为零向量。 n m ≤ 5 × 1 0 5 nm\le 5\times 10^5 nm5×105

思路

第一个思路是,红蓝可以独立搞。如果蓝点的总数 n m nm nm 是个奇数,那么每个点的度数都是偶数,直接走一条欧拉回路就可以了。

第二个思路是,如果 n m nm nm 为偶数,就把它 转化 为第一种思路。题目中有个奇怪的限制:左上角为红色,右下角为蓝色。看来它们比较 特殊。那就先不管这两个点,其他的点按照思路一去搞就行。

然后只剩这俩了。如果两个向量之和为零向量,那么它们 中心对称。这两个点不就是中心对称吗?试一试,能不能按照中心对称的方法搞?

对于一个格点,不妨设其为蓝点,如果其中心对称点是红点,分别与角落连就行——必然形成两个中心对称的向量,其和为零。如果对面也是蓝点?还是一起往角落连。此时,形成了一个 恰为主对角线 的向量。

由于红蓝点数量相同,形成的主对角线向量也同样多。刚好抵消了!

题目描述

给定一个长度为 n n n 的环,环上的点有三种颜色 R , G , B R,G,B R,G,B 。若一个点两边的点是异色的,你就可以任意改变这个点的颜色为 R , G , B R,G,B R,G,B 中的一种。问能否在 10 n 10n 10n 次操作内,把一个环变为另一个。如果能,输出方案。 5 ≤ n ≤ 1 0 5 5\le n\le 10^5 5n105

思路

不能操作很容易嗝屁。所以,我们先处理掉这个问题,让每个点都变的可以操作。这是容易实现的:先找到一个可操作的点,不妨让其为 1 1 1 号点,然后将其修改成与 3 3 3 号点、 n − 1 n-1 n1 号点颜色均不相同。然后 2 2 2 号点可以操作了,将其修改成与 4 4 4 号点、 n n n 号点颜色均不相同。然后 3 3 3 号点可以操作了……到最后,把 n n n 号点修改完的时候,所有点都可以操作了。只需要恰好 n n n 次操作,挺高效的!

然后我们考虑直接变换。将 1 1 1 号点修改为目标串 1 1 1 号点的颜色。可能导致 2 2 2 号点无法操作!额外再操作一下 3 3 3 号点(规则同上——使得两边的点都可以操作)。然后再操作 2 2 2 号点, 4 4 4 号点给它擦屁股。操作 3 3 3 号点, 5 5 5 号点来帮忙。如此等等。可是,到操作了 n − 2 n-2 n2 号点,想要让 n n n 号点帮它弥补过错的时候,不一定满足 n n n 号点可以操作了……

心若在,梦就在,只不过是从头再来 ♪ \large ♪ 在刚刚修改了 1 1 1 号点的时候,不仅要额外操作 3 3 3 号点,更要修改一下 n − 1 n-1 n1 号点。所以最后一步就高枕无忧了。 n n n 号点可以被修改。然后让 n − 1 n-1 n1 号点的颜色与目标串相同,接下来要操作 n n n 号点……

没错,目标串必须满足 n − 1 n-1 n1 号点的颜色与 1 1 1 号点不同。那么我们直接在目标串上找到这样的两个点,使其为 n − 1 n-1 n1 号点和 1 1 1 号点即可。什么?找不到怎么办?要是找不到,那么目标串上任意一个点都没法被操作,容易发现,这种情形下是不可能通过操作获得目标串的——除非二者天生相等。

总操作次数是 n + 2 ( n − 2 ) + 2 = 3 n − 2 n+2(n-2)+2=3n-2 n+2(n2)+2=3n2 的。

题目描述

一个 n × n n\times n n×n 的数字矩阵,你可以执行的操作是:

if(cell[A] < cell[B]) rotate(C)

rotate 会逆时针旋转你指定的 2 × 2 2\times 2 2×2 子矩阵 C C C。当然, A , B A,B A,B 也是你指定的格子。

你可以任意次进行操作。用 A i j ( i , j ∈ [ 1 , n ] ) A_{ij}(i,j\in[1,n]) Aij(i,j[1,n]) 表示第 i i i 行第 j j j 列的数字,你只需要使得结果满足 ∀ i ∈ [ 3 , n ) , A i n ≤ A ( i + 1 ) 1 \forall i\in[3,n),A_{in}\le A_{(i+1)1} i[3,n),AinA(i+1)1 ∀ i ∈ [ 3 , n ] , j ∈ [ 1 , n ) , A i j ≤ A i ( j + 1 ) \forall i\in[3,n],j\in[1,n),A_{ij}\le A_{i(j+1)} i[3,n],j[1,n),AijAi(j+1) 。直观来说就是:下面 n − 2 n-2 n2 行首尾相接形成一个不下降序列。

有趣的是,你不知道矩阵的模样。也就是说,无论何种数字矩阵,经过操作后都可以成功! 3 ≤ n ≤ 9 3\le n\le 9 3n9

思路

考虑每次找出整个数字矩阵中的最大值,然后从后往前填入。假设目前要把 ( x , y ) (x,y) (x,y) 放好(也就是说,下面的 n − x n-x nx 行和第 x x x 行末尾的 n − y n-y ny 列已经填好)。

我们只能靠 if 知道大小,那么我们想办法把一行的最大值推到一侧去(事实上,对一列也成立)。方案就是从左往右扫,如果 A i j > A i ( j + 1 ) A_{ij}>A_{i(j+1)} Aij>Ai(j+1) 就以 ( i − 1 , j ) (i-1,j) (i1,j) 为左上角旋转,判断三次(因为有可能把第 i − 1 i-1 i1 行的数字旋转下来了)。此时 A i n A_{in} Ain 一定是第 i i i 行的最大值。

i i i x − 1 x-1 x1 循环到 2 2 2 ,最大值都集中在了最左边一列。同样的方法,可以从这些 “最大值” 中筛出真正的最大值,放到了矩形右上角。由于第一行还没有被考虑,我们就让第一行从右往左冒泡排序即可。(如果 A 1 i < A 1 ( i + 1 ) A_{1i}<A_{1(i+1)} A1i<A1(i+1) 就以 ( 1 , i ) (1,i) (1,i) 为左上角旋转。)

此时最大值在左上角。然后把它推到 ( x − 1 , 1 ) (x-1,1) (x1,1) 去。为什么要在这里驻足?因为你会发现,第 x x x 行左边 y y y 列的数字没有被考虑。所以我们又开始了遴选过程。如果 A ( x − 1 ) 1 > A x 2 A_{(x-1)1}>A_{x2} A(x1)1>Ax2 就以 ( x − 1 , 1 ) (x-1,1) (x1,1) 为左上角旋转。然后一个冒泡就行。

驻足的第二个考虑是 y = 1 y=1 y=1塞不进去!我们得先把旁边的两个转一下——如果 A x 3 > A x 1 A_{x3}>A_{x1} Ax3>Ax1 就以 ( x − 1 , 2 ) (x-1,2) (x1,2) 为左上角旋转。根据我们的过程, A x 1 ≤ A x 2 ≤ A x 3 A_{x1}\le A_{x2}\le A_{x3} Ax1Ax2Ax3 。假如 A x 1 = A x 3 A_{x1}=A_{x3} Ax1=Ax3 ,那么 A ( x − 1 ) 1 ≤ A x 3 = A x 1 A_{(x-1)1}\le A_{x3}=A_{x1} A(x1)1Ax3=Ax1 ,不用想啦,不用塞进来!但是注意:下面的操作针对这种情况都会变成无用操作,这样就能保证它不变了。

所以,更有可能的是 A x 1 < A x 3 A_{x1}<A_{x3} Ax1<Ax3 ,那么就完成了旋转。下一步,如果 A ( x − 1 ) 1 > A x 1 A_{(x-1)1}>A_{x1} A(x1)1>Ax1 就以 ( x − 1 , 1 ) (x-1,1) (x1,1) 为左上角旋转,就把它塞进来了。这时候得把原来的那两位转回来:如果 A ( x − 1 ) 3 > A x 1 A_{(x-1)3}>A_{x1} A(x1)3>Ax1 就以 ( x − 1 , 2 ) (x-1,2) (x1,2) 为左上角旋转;如果 A ( x − 1 ) 2 > A x 1 A_{(x-1)2}>A_{x1} A(x1)2>Ax1 就以 ( x − 1 , 2 ) (x-1,2) (x1,2) 为左上角旋转;如果 A x 2 > A x 1 A_{x2}>A_{x1} Ax2>Ax1 就以 ( x − 1 , 2 ) (x-1,2) (x1,2) 为左上角旋转。不难发现,此种情况下,一定旋转了 3 3 3 次,恰好就回来了。

对于一个格子基本上要操作 O ( n 2 ) \mathcal O(n^2) O(n2) 次,所以总操作 O ( n 4 ) \mathcal O(n^4) O(n4)

中场休息

题目描述

构造一个长度为 n n n 的数字数列,使得 m m m 个限制条件都被满足。限制条件形如 max ⁡ ( a i , a j ) = v \max(a_{i},a_{j})=v max(ai,aj)=v min ⁡ ( a i , a j ) = v \min(a_i,a_j)=v min(ai,aj)=v 。数据范围 max ⁡ ( n , m ) ≤ 1 0 5 ,    1 ≤ i , j ≤ n ,    0 ≤ v < 2 31 \max(n,m)\le 10^5,\;1\le i,j\le n,\;0\le v<2^{31} max(n,m)105,1i,jn,0v<231

思路

然而是 2 - s a t {\tt 2}\text{-}{\tt sat} 2-sat 的题。为了让大家放松一下的。

首先可以算出每个数字的上下界。并且很显然,每个数字要么取上界、要么取下界(不然对于满足限制条件没有任何帮助)。然后每个限制条件就变成了,如果一边不选上或下界,另一边就要选。所以嘛……

题目描述

有一棵有根二叉树,共 n n n 个节点,每个节点上都有一个数字 f ( x ) f(x) f(x) 。叶子节点的值可能是 0 0 0 1 1 1 ,但是对于非叶子节点,其 f f f 值为两个儿子节点的与非。形式化地,设两个儿子节点为 a , b a,b a,b f ( x ) = ¬ [ f ( a ) ∧ f ( b ) ] = max ⁡ [ 1 − f ( a ) , 1 − f ( b ) ] = 1 − min ⁡ [ f ( a ) , f ( b ) ] f(x)=\neg[f(a)\wedge f(b)]=\max[1-f(a),1-f(b)]=1-\min[f(a),f(b)] f(x)=¬[f(a)f(b)]=max[1f(a),1f(b)]=1min[f(a),f(b)]

你要钦定一些叶子节点的取值,使得这两个条件成立:

  • 没有被钦定的叶子结点都取 1 1 1 时,根节点的值与所有叶子节点都取 1 1 1 的情况下相等。
  • 没有被钦定的叶子节点都取 0 0 0 时,根节点的值与所有叶子节点都取 0 0 0 的情况下相等。

如何最大化钦定的点的数量?给出方案。 n ≤ 1 0 5 n\le 10^5 n105

思路

答案的上界是 n n n ,毫无疑问 😉 用 g ( x 1 , x 2 , … , x k ) g(x_1,x_2,\dots,x_k) g(x1,x2,,xk) 表示, k k k 个叶子节点的取值分别为 ⟨ x ⟩ \lang x\rang x 时,根节点的值是什么。那么,只有 g ( 0 , … , 0 ) = g ( 1 , … , 1 ) g(0,\dots,0)=g(1,\dots,1) g(0,,0)=g(1,,1) 时,这一点才能做到。

否则,我们退而求其次,可不可以钦定 n − 1 n-1 n1 个点呢?这一个构造很巧妙: s ( x ) = g ( 1 , 1 , … , 1 ⏟ x 个 1 , 0 , … , 0 ) s(x)=g(\underbrace{1,1,\dots,1}_{x个1},0,\dots,0) s(x)=g(x1 1,1,,1,0,,0) ,那么 g ( 0 ) ≠ g ( n ) g(0)\ne g(n) g(0)=g(n) ,并且我们想找到一个 x x x 满足 g ( 0 ) = g ( x ) ∧ g ( x + 1 ) = g ( n ) g(0)=g(x)\wedge g(x+1)=g(n) g(0)=g(x)g(x+1)=g(n) 。这样一来,我们就可以留下第 x + 1 x+1 x+1 个叶子,作为不钦定的了。

显然 “二分法求函数零点” 即可。复杂度 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)不过你怎么敢猜想,一定是前缀全部钦定为一、后缀全部钦定为零的呢?

拾壹

题目描述

一个 n n n 个点简单无向图(不保证连通),你可以询问若干次,每次询问一棵 n n n 个点的树,交互库会告知你这棵树上有多少条边在原图中出现了。

你需要还原这个图。 n ≤ 500 , m ≤ 2000 n\le 500,m\le 2000 n500,m2000 ,询问次数不得超过 20000 20000 20000(事实上,如果超过了,你也差不多该 T L E \rm TLE TLE 了)。

思路

从简单入手。如果不要求询问的树包含 n n n 个点怎么办?对于每个点都求出它的连边就行。

用分治,因为边数 m m m 远小于 n 2 n^2 n2 。在 O ( m log ⁡ n ) \mathcal O(m\log n) O(mlogn) 的询问次数内足以完成任务。

问题是,我们询问的必须是生成树。预处理一些特殊边,如果我知道这些边的出现情况,那么我就可以用这些边把前面的询问补充成树。这些特殊边可以就是 ⟨ i , i + 1 ⟩ \lang i,i+1\rang i,i+1 。但是怎么求出其中每条边的出现次数呢?加上边 ⟨ n , 1 ⟩ \lang n,1\rang n,1 形成了环,去掉每一条边的结果都询问一次。这 n n n 个结果的和除以 n − 1 n-1 n1 即每条边的出现情况之和,然后分别作差即可知道。

总次数 O ( m log ⁡ n + n ) \mathcal O(m\log n+n) O(mlogn+n)或许略卡常?

拾贰

题目描述

有一个 n × m n\times m n×m 的矩阵,你可以执行以下三种操作若干次,使得整个矩阵里所有元素都变成 0 0 0

  1. 把某一行里的元素全部加上整数 k k k
  2. 把某一列里的元素全部加上 k ( k ∈ Z ) k(k\in\Z) k(kZ)
  3. 把某一主对角线(指行和列编号之差为定值)里的元素全部加上整数 k k k

你可以执行这些操作共 6000 6000 6000 次,或者报告无解。 2 ≤ n , m ≤ 1 0 3 2\le n,m\le 10^3 2n,m103

思路

只需让前两行两列都是零。证明:对于任意 3 × 3 3\times 3 3×3 的矩阵, a 11 − a 12 − a 21 + a 23 + a 32 − a 33 a_{11}-a_{12}-a_{21}+a_{23}+a_{32}-a_{33} a11a12a21+a23+a32a33 是定值。所以,如果有解,前两行前两列均 0 0 0 的时候, a 33 a_{33} a33 也就为 0 0 0 ,然后 a 34 , a 35 , … , a 3 n a_{34},a_{35},\dots,a_{3n} a34,a35,,a3n 依次都可以推出为 0 0 0 。而后第 4 , 5 , … , n 4,5,\dots,n 4,5,,n 行必然也均为 0 0 0 。证毕。

而前两行两列为零是很容易的。以前两行为例,从第 n n n 列处理到第 1 1 1 列,比如处理到了第 j j j 列。先用列操作,使得 a 1 j = 0 a_{1j}=0 a1j=0 ,然后用对角线操作使得 a 2 j = 0 a_{2j}=0 a2j=0 。前两列同理——先行再对角即可。

只需要操作约 2 ( n + m ) = 4000 2(n+m)=4000 2(n+m)=4000 次,然后检查矩阵是否全零即可。

拾叁

题目

传送门 to CF:太长了,不想翻译。

思路

对值域 分块。考虑将 a x ∈ [ L , R ] a_x\in[L,R] ax[L,R] 的所有 x x x 从小到大排序为 x 1 , x 2 , x 3 , … , x k    ( k = R − L + 1 ) x_1,x_2,x_3,\dots,x_k\;(k=R-L+1) x1,x2,x3,,xk(k=RL+1),然后对于 1 ≤ l < r ≤ k 1\le l<r\le k 1l<rk 预处理出所有合并了 x l , x l + 1 , … , x r x_l,x_{l+1},\dots,x_{r} xl,xl+1,,xr 的区间。询问的时候直接取出即可。询问的复杂度是 O ( q n B log ⁡ B ) \mathcal O(q\frac{n}{B}\log B) O(qBnlogB) 的,合并次数是 q n B q\frac{n}{B} qBn 的。

然后怎么预处理呢?考虑值域 分治。因为 x l , x l + 1 , … , x r x_l,x_{l+1},\dots,x_{r} xl,xl+1,,xr 满足 a x ∈ [ L , M ] a_x\in[L,M] ax[L,M] 的,在所有满足 a y ∈ [ L , M ] a_y\in[L,M] ay[L,M] y y y 中也是连续区间。所以递归后合并即可。复杂度 T ( B ) = 2 T ( B 2 ) + O ( B 2 ) = O ( B 2 ) T(B)=2T({B\over 2})+\mathcal O(B^2)=\mathcal O(B^2) T(B)=2T(2B)+O(B2)=O(B2),合并次数 T ( B ) = 2 T ( B 2 ) + B ( B − 1 ) 2 = B 2 − 1 2 B log ⁡ B T(B)=2T(\frac{B}{2})+\frac{B(B-1)}{2}=B^2-\frac{1}{2}B\log B T(B)=2T(2B)+2B(B1)=B221BlogB 。为了让合并次数最小,需要
n B ( B 2 − 1 2 B log ⁡ B ) + q ⋅ n B ≤ n B + q n B \frac{n}{B}\left(B^2-\frac{1}{2}B\log B\right)+q\cdot\frac{n}{B}\le nB+\frac{qn}{B} Bn(B221BlogB)+qBnnB+Bqn

最小,取 B = q B=\sqrt{q} B=q 最优,合并次数与复杂度均为
O ( n q ) \mathcal O(n\sqrt{q}) O(nq )

拾肆

题目

传送门 to CF:有一个 [ 0 , n ) [0,n) [0,n) 的 “排列”,每次可以询问任意两个元素的按位或的值,请在 4269 4269 4269 次询问内还原该序列。 n ≤ 2048 n\le 2048 n2048

思路

只需要知道 0 0 0 的位置。考虑从左往右扫,维护两个备选的 0 0 0 的位置 a , b a,b a,b,设当前位置为 c c c,比较 c or ⁡ a c\operatorname{or}a cora b or ⁡ a b\operatorname{or}a bora 的值。因为 ∀ x ,    x or ⁡ a \forall x,\;x\operatorname{or}a x,xora 的最小值之一必然为 x = 0 x=0 x=0 时取得,如果二者不相等,较大的那个一定不为零。

如果二者相等呢?说明 a a a 不为零 。因为 a = 0 a=0 a=0 就可以推出 b = c b=c b=c,这是荒谬的。所以我们必然排除三者之一。最终剩下的两个数,可以随机挑一个第三者,然后与二者求按位或。因为仅当第三者是非零的数的超集时,可能会相同。而每一位被包含的概率是 1 2 \frac{1}{2} 21,哪怕非零的数是 2 k 2^k 2k,询问 30 30 30 次也只有 2 − 30 ≈ 1 0 − 9 2^{-30}\approx 10^{-9} 230109 的概率一直无法判断。

由于只能用大约 n n n 次询问得到 0 0 0,必须对 a , b a,b a,b 先行求出 b or ⁡ a b\operatorname{or}a bora 才行。如果排除的是 b b b,剩下的是 ⟨ a , c ⟩ \langle a,c\rangle a,c 就不需要重新计算,因为判断的时候求过了。只有第三种情况,两个按位或的值相等,会导致我们需要重新计算 b or ⁡ c b\operatorname{or}c borc 的值。难道是 2 n 2n 2n 次询问么?

事实上,第三种情况极难发生。那种情况很苛刻,需要 b = 0 b=0 b=0 c ⫋ a c\subsetneqq a ca 才行。可一旦 b = 0 b=0 b=0 之后,只要 c ⫋ a c\subsetneqq a ca 不成立,就会把 c c c 扔掉,否则进入第三类。那么 a a a 1 1 1 的个数只会减小。那么最多减小 log ⁡ n \log n logn 次。那么操作次数最多是
2 n + ⌈ log ⁡ n ⌉ + 30 = 4137 2n+\lceil\log n\rceil+30=4137 2n+logn+30=4137

就这样,问题解决了。巧妙利用了按位或的大小关系。

拾伍

题目

传送门 to CF:有一个序列,每次可以询问一些位置上的数字的按位或。你需要在 13 13 13 次操作内得到:原序列去掉任意一个数字后,剩余的数字的按位或。 n ≤ 1 0 3 n\le 10^3 n103

思路

第一反应是二进制分组。然而它恰好需要 2 log ⁡ n = 20 2\log n=20 2logn=20 次,稍微多了一点。

这是一种从来没见过的方法:把 n n n 个数字重新映射到一组数上。我们把所有 不超过 2 13 2^{13} 213 的、恰有 6 6 6 个二进制位为 1 1 1 的数字 拿出来,代表那 n n n 个数字。由于 ( 13 6 ) = 1716 {13\choose 6}=1716 (613)=1716 超过了 1000 1000 1000 个数字,必然可以映射。用 f ( x ) f(x) f(x) 表示。

做完了映射,再记
S k = { x    ∣    f ( x ) and ⁡ 2 k ≠ 0 } S_k=\{x\;|\;f(x)\operatorname{and}2^k\ne 0\} Sk={xf(x)and2k=0}

把每个 S k S_k Sk 集合内的元素的按位或都求出,记为 w k w_k wk 。此时,对于原序列去掉 i i i 的答案就是
{ w j    ∣    f ( i ) and ⁡ 2 j = 0 } \{w_j\;|\;f(i)\operatorname{and}2^j=0\} {wjf(i)and2j=0}

因为 f ( i ) f(i) f(i) 恰好有 6 6 6 个二进制下的 1 1 1,所以 f ( i ) ≠ f ( j ) f(i)\ne f(j) f(i)=f(j) 则必然存在一个二进制位使得 f ( i ) f(i) f(i) 中这一位为 1 1 1 f ( j ) f(j) f(j) 中这一位为 0 0 0 。(这一步很神奇,在最初的二进制分组中,可能是 i i i 0 0 0 j j j 1 1 1,在此处则不可能。)

所以这道题就做完了。总结起来就是:二进制分组本来是 log ⁡ n \log n logn 的,却因为有 i ⫌ j i\supsetneqq j ij 的情况,而迫不得已求了 2 log ⁡ n 2\log n 2logn 个。如果规定 1 1 1 的数量相同,那就避免了包含关系,进而可以 1 log ⁡ n 1\log n 1logn 了。

拾陆

题目

传送门 to CF:对于给定的正整数数列 ⟨ a 1 , a 2 , … , a n ⟩ \langle a_1,a_2,\dots,a_n\rangle a1,a2,,an,你每次可以选择一个集合 S S S 并且将集合内所有数字减小一。请用不超过 n + 1 n+1 n+1 次操作把所有数字变成 0 0 0,同时满足任意两次的操作集合都不同。 a i ≤ n ≤ 1 0 3 a_i\le n\le 10^3 ain103

思路

将题意转化一下:求一个 n + 1 n+1 n+1 n n n 列的 0 / 1 0/1 0/1 矩阵,每一列的 1 1 1 的个数有限制,任意两行不完全相同。

自己动手来找找感觉。比如每一列都需要 n n n 1 1 1 的时候怎么做?可以挖掉一个对角线。

这给了我们一个启发:把对角线空出来。我们可以把数字从小到大排列,对于第 i i i 列,我们从第 i + 1 i+1 i+1 行开始,填连续的 a i a_i ai 行(如果到底部就从顶端继续)。这样列的限制就已经满足了。而行显然是不会相同的,毕竟我们按照 a a a 从小到大排序了。

更多

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值