好题选写

P2476

很好的绿 dp,场上卡我 2h,场上只考虑了二进制状压,然后组合数填数,最后发现没法去除重复情况。

说一下简单的正解,这题组合数也是能搞的,只是需要多开一维记录当前存在多少相邻的同色位置。考虑到 ci5,我们记录每种颜色个数的个数,然后按照个数记忆化爆搜,这样一想就很简单了。具体地,我们令 f(a,b,c,d,e,las) 表示 1 - 5 每种颜色还有多少,上一次是在哪一类数量选的,因为一个数字用完之后会扔到下一维,防止两种相同颜色在一起,所以要减掉 1

code

P2051

以为是挺简单的 dp,结果场上没写出来。

发现每一列/行只有三种情况,有 0/1/2 个棋子,假如我们枚举行,限定行的放置个数,就只需要考虑列的情况了,具体地,我们只需要维护前 i1 列的放置情况即可。令 f(i,j,k) 表示前 i 行,j 列有一个棋子,k 列有两个棋子,另外没有棋子的列可以表示为 mjk,可以直接考虑转移。

当新拓展的一行不放棋子的时候: f(i+1,j,k)=f(i,j,k)

当新的一行放一个棋子的时候,分类讨论是增加哪种列:

f(i+1,j+1,k)=f(i,j,k)×(mjk)

f(i+1,j1,k+1)=f(i,j,k)×j

放三个棋子的时候同理讨论转移:

f(i+1,j+2,k)=f(i,j,k)×(mjk2)

f(i+1,j,k+1)=f(i,j,k)×j×(mjk)

f(i+1,j2,k+2)=f(i,j,k)×(j2)

注意取模,统计答案即可。

code

P5304

之前集训的时候就听过的 trick,没想到这场考了,竟然还是不会,我是菜b。

首先,我们暴力枚举再最短路的复杂度是 O(k(n+m)logm)。显然是爆炸的,我们考虑二进制分组,我们每次划分两个集合 {A}{B},按位枚举关键点,这一位为 1 的扔到 A 集合,否则扔到 B 集合,再对一个集合连超级源点,跑一遍最短路即可。会发现,假如答案的左右端点不同,那么他们至少有一位是不同,所以会有至少一次被跑最短路,答案是正确的,复杂度 O(Tnlognlogk),虽然还有 O(Tnlogn) 的做法,但这种 trick 倒是很神奇的。

注意两个集合需要互相跑最短路,要建两个图。

code

AT_dp_q

场上还以为能评个蓝,一开始看到有人 10min 过了,吓一跳,疯狂写,然后假了一次 (。

考虑设计 f(i) 表示以 i 位置结尾的上升子序列的最大价值和,转移是 f(i)=maxaj<ai{f(j)}+hi,然后就可以用线段树维护 f 数组的前缀 max 和单点修改即可,这种东西卡了我 40min,菜死了菜死了菜死了菜死了。

code

P6273

上场卡死我的唐题,对标 2023CSP-S T2,真唐完了,今年不会 CSP 还是个 2= (。

场上考虑了类似消消乐那题的答案合并,发现两个答案区间并起来也是合法的,所以我们可以用类似消消乐的方式跳链表维护,但显然这样是假的,随便构造一组类似 baaaaaaaa... 的样例就卡爆了。

正解,注意到,令 si,k=j=1i[Si=k],则我们判断一个区间合法的标志就是 aTprer,aprel1,a=k,此处 k 是一个正整数,换句话说,假设我们固定一个字母用来表示 k,则这个式子写作 prer,aprel1,a=prer,bprel1,b,把式子移项,得到,prer,aprer,b=prel1,aprel1,b 那么我们只需要记录每个位置每个字母和这个固定字母的差值,哈希一下扔进 map 里面,记个数即可。

code

P10083

很好的体现了场上没用草稿纸的问题,考虑分析区间合法的充要条件。

  • 区间的总和不能为负,即 i=lr(biai)0,记作一式

  • 任意时刻,我们都必须能打出下一张牌,最坏情况就是把所有负收益的放在前面打出来,即 Ei=lrmax{0,aibi}maxi=lrai[ai<bi]

  • 进一步考虑,在上述情况下,我们还要考虑负收益的牌这时候能不能打出来,最坏情况肯定就是它是最后一张负收益的牌,然后判断是否合法,即 Ei=lrmax{0,aibi}maxi=lrbi[ai>bi]

整理一下后两个式子,写作 Ei=lrmax{0,aibi}maxi=lrmin{ai,bi},记作二式。

则我们需要同时满足两个式子,分别讨论:

  • 对于第一个式子,令 prei=j=1i(biai),则第一个式子为 prerprel10,即 prerprel1

  • 对于第二个式子,可以发现,左边式子单调不增,右边式子单调不减,存在这样的性质,我们可以直接双指针维护。

具体地,我们可以拿 ST 表维护二式右边式子,然后每次双指针拓展到最远的 r 点,用 BIT 离散化前缀和后计数即可。

code

P10930

两个多月之前做的了,题挺好的,写一下。

现在我们要在树上支持三个操作。加特殊点,抹除特殊点,求特殊点路径覆盖边的长度。这种东西看起来挺难搞的,那我们就一步一步模拟着来看。

人类直觉做法,发现所有情况可以分类讨论,假定当前点为 u,我们肯定是要找他前后最优的点来计算路径,这里是可以直接二分的,可能会发现有情况满足取的不会是最近的点,但是这种是不影响结果的,放到了下面去讲。

只有前驱或者只有后继的情况没什么好讨论的,我们考虑一般情况。

拟定当前的根有三棵子树,每棵子树下挂着一堆点,令 u 在中间子树的某个节点上,他下面也有子节点。

image

画出图类似这样,我们记根的三棵子树分别为 xyz,特别地,我们令 y 子树内 x 往上到根的部分记作 v,往下的部分记作 w

此处以增加为例,删除同理,讨论三个点的位置关系,前驱为 pre,后继为 nxt

  • prex 子树内,nxtw 内,就不画图了,抽象理解一下,我们需要加上 dis(pre,x)+dis(x,nxt)dis(pre,nxt)

  • prex 子树内,nxtz 子树内,我们需要加上 dis(pre,x)+dis(x,nxt)dis(pre,nxt)dis(x,root),此处 root 为根节点。

  • prev 内,nxtw 内,同情况一。

  • prev 内,nxtz 内,我们需要加上 dis(pre,x)

我们将每种情况的加减都变为 dis(pre,x)+dis(x,nxt)dis(pre,nxt),情况一三不变,情况二少了 x 到根的答案,情况四多算了 dis(x,pre),发现这两种情况下我们如果加上 dis(pre,nxt),答案就是正确答案的二倍,进一步拓展这个结论,通过拼接几种情况,我们最后需要加上 dfn 最小的到 dfn 最大的路径长度就能使得所有边正好被经过两次,这个可以自己去手动模拟一下,这种结论挺抽象的,可以类似环尾再走到环首。

还有上面说到取的不是最近点的问题,就是类似情况三的时候,子树 z 上还有点距离 x 更近,发现此时我们按照上述方法更新的话增加这个点和没有增加的路径长度是一样的,所以说对答案并不会产生影响。

set 维护特殊点,二分 dfn 序再算答案就好了,复杂度 O(nlogn)

补:过了 P3320 这个结论应该会更好理解一些,就是走过去再从终点走回来,每条边都被覆盖两次,再除掉就好了。

code

P4137

回滚莫队基础练习题,可是我们不会回滚莫队,考虑另类做法。

使用回滚的原因,是 mex 不好进行添加操作,复杂度容易退化,我们考虑一种方式维护增加,首先很好想的就是权值线段树上二分找前缀 1 的和是否等于区间长度,这个实现起来也比较简单,可是复杂度是 O(nnlogn+nlog2n),对于 2e5 的数据是无法通过的。

在思考,发现这种算法的瓶颈还是在于添加的 log,我们考虑使用添加 O(1) 的数据结构再维护,没错,还是分块。我们考虑对于值域再次分块,这样就可以直接进行修改了,查询时也不需要二分,直接便利每一个块看哪一个块中有空缺的与元素就好了,这样复杂度是 O(nn+nV) 的,其中 V 是值域,可以通过,而且跑得飞快。

code

ABC298E

开学之后感觉就开始颓了,做点简单题。

概率 dp,我不会的东西,考虑大力 dp,设 f(i,j) 表示 A 已经有 i,B 已经有 j 的概率。

直接大力转移:f(i+min{n,i+x},j+min{n,j+y})+=f(i,j)×1p×q

复杂度 O(n2pq),完全能过。

code

P8025

感觉好久没更新了,最近做题好慢啊,写简单题。

题意就是每次树上俩点走 k 步走到哪,不能到达就输出最远的点。

这东西显然是可以大力树剖的,发现转折点是一个关键的点,前半段上升,后半段下降,分类讨论就好了。记 depu 表示节点 u 的深度,那么从 u 点走到 lca 的步数就是 depudeplca,下降同理。

  • depudeplca<k 的时候,说明一定走不到,我们直接考虑跳链,一条链的链头记作 tx,当 depudeptx<k 的时候,说明这一条链都不符合答案,继续跳即可,反之则答案就在这条链里面,答案是显然具有单调性的,直接在链上二分即可,这里就是树剖的性质,一条链上的节点编号是连续的。

  • depudeplca=k 的时候,答案就是 lca

  • 否则,答案就在下降路径上,上升路径的步数是固定的,直接减去即可,然后类似上升过程中的跳链做法,判断步数在最后一条链上二分找答案即可。

复杂度 O(nlog2n)

code

P1654

不会期望,所以刷点水期望 dp。

发现这个连续段不好搞,转成一个一个增加来看,假如有原答案 x,我们新增加一个 1,那么答案的变化是 (x+1)3=x3+3×x2+3×x+1,相对于原答案增加 3×x2+3×x+1,然后对 xx2x3 分别 dp 就好了。

code

CF1997E

差点场切的 *2200,一个月前做的,补一下题解,虽然也是一个多月前写的(。

写一下 E 吧,毕竟想了我好久。不会正解 BIT,写暴力根号分治,也就比正解慢了 1000ms 而已(?)。

首先,我们能够想到一种暴力,我们离线下来询问,依次按照 ix 排序,然后我们对于每一种 i 处理答案,对于 i 的种类少的数据跑得很快,但是这种做法容易被 i 多的极端数据卡到 n2。然后,我们再考虑优化一点的方案,对于每次够了 k 次,我们都可以二分出这个位置,查询区间内可以用主席树做到 log2,看着感觉复杂度挺对的,可是对于一堆 i 很小的数据,我们的二分可能会退化,也有缺陷。考虑将这两种算法结合,对于 iV 的查询,我们可以用第一种方案暴力算,其中 V 是阀值,然后这样由于阀值的限制,第一种的复杂度就可以控制在 O(n),然后 i>V 的用第二种算,还是因为阀值的限制,复杂度可以得到控制,这样做总体的复杂度是 O(nn+nlog3n) 的,会发现,被卡了 (。

考虑哪里还能再优化,发现当 i>V 的时候,我们的等级最多会升到 nV,这就解决了前缀和爆数组的问题,简单算一下,V 取到 nlogn 的时候最好,数组开到 2e5×120 就够了,然后先按照每个数算一遍前缀和,再记一个前缀和扫另一个前缀和,相当于扫了一个二维平面吧(?),就可以做到 O(1) 的获取区间答案了,少了两只 log,复杂度 O(Vn+nnlogn+nmVlogn),跑了 1400+ ms,挺好的。

code

P5648

感觉是很神奇的题,首先会有一个跳 max 的思路,可是这样显然会被类似单调递增序列卡掉,我们考虑如何优化。

发现这种跳的过程我们很类似的会用在倍增求 LCA 中,我们往哪方面想,假如我们将一步跳跃看做树上一跳向上的边,那么我们最后的答案就是求树上前缀距离了,这就很简单了。

神奇的,code

P5789

口胡成功力。

先不管它是怎么走的,先考虑一个点可能怎么走来,显然就是和它相连的点的方案数相加对吧,写成转移方程,令 fi 表示第 i 个点的方案数,那么每增加一秒,他的答案就变成 fi=fi+fj1+fj2+...,这种东西就很像数列加速的样子对吧,所以我们直接写成矩阵,(i,j)1 当且仅当他们之间有边,由于 n,m100,所以这样做是对的。

再考虑,还有自爆和不动的情况,自爆我们可以连一个点到外面,然后让那个点连自环,然后再让每个点跟自己相连,就处理了不动和自爆的情况,就完了。

code

ABC332F

简单期望,期望做的还是少,还在考虑和后面有一点捆绑关系。

考虑当一个区间新增时,对于一个在区间内的值 val 的修改就是令他变为 val×rlrl+1+k×1rl+1,然后还有区间修改,那么这就是一棵区间乘,区间加,单点查询的线段树了。

code

P3979

经典 tick 树剖换根,虽然树剖没有办法直接换根,但是我们可以分类讨论解决。

简单分析可得,记当前点为 u,根为 root,我们以 1 号点建树剖,假如 u1root 路径上,那么换根对树剖就是有影响的,此时的答案区间就是不包含 root 所在的 u 子树区间,取个补集就好了,其他情况没变化,注意特判 rootu 重合的情况。

code

ABC371F

好题。为什么好?因为我不会。

首先能够想到每次向左向右会使得一整块棋子向目标点右边偏移,这就需要我们二分处理,是可以做的,处理之后,区间推平,再覆盖一个等差序列就好了,这样做是可以的,但是麻烦,考虑简单做法。

第一次见这个 trick,考虑令 aiaii,那么我们推平等差数列的操作就变成区间赋值了,然后我们二分向右找是 2log 的,这里选择线段树上二分,虽然这也是第一次学,但是也是简单的,其实线段树上二分就和普通二分差不多,还是要求单调性,每次的决策扔到线段树节点上就好了,跟普通二分的决策方式是一样的,可是线段树二分的复杂度是 O(nlogn) 的,总复杂度 O(n+qlogn)

code

P8817

赛前写写真题了属于是,还是挺简单的。

由于每段路程都是分开的,只有选点不能重复这一个条件,我们可以把所有点走 k+1 步能走到的点都找出来,复杂度是 O(n2),用 vector 存下来,发现这样就可以把图缩小,每条边连接的点代表他们之间的距离小于等于 k,这与原图是显然等价的。我们现在只需要考虑选点不重复这一个难题了,猜想复杂度肯定是 O(n2),发现可以枚举中间两个点 BC,然后 A 的取点范围就是 1B 取点的交集,D 的取点就是 C1 取点的交集,取交集这一步也可是 O(n2) 完成,然后直接贪心就好了,我们直接拿点集最大值进行匹配,当有重复点时,取次大点即可,可是发现可能 B 的次大值也与 C 重复,所以还要取一个次次大值,然后拿两边的 3 个值互相比较就做完了,复杂度 O(n2)

一发过,好耶。

code

P11253

开颓,不会绿。

感觉很抽象啊,注意到 i! 可以 O(n) 预处理,并且 (ij)k=ik×jk,所以,这东西可以欧拉筛筛出来,因为质数个数约为 nlogn,所以复杂度是 O(n),要卡一卡常。

code

CF809C

模拟赛场上会了单点求值的办法,没想到前缀求和,无敌了。

一种不用注意力的方法,通过打出 30×30 的表来可以发现这是个分形的东西,一大个大矩形的长度为 2k,那么他就可以被分为边长为 2k2k12k2k1 的四个小矩形,而且可以观察得出大矩形的每一行都是一个 2k 的排列,你甚至还可以得出他的分形规律,但对正解没什么用。

每次询问一个矩形的答案,自然可以差分变成询问四个左上角在 (1,1) 的小矩形的答案,现在就要考虑怎么求一个覆盖左上角的矩形的答案。

由于这个东西的特性,我们先将他向外补到 2k,然后讨论他右下角点的位置:

像这样,假设他在右下角,那么蓝色部分就是一个完整的边长为 2k1 的矩形,通过之前观察发现他的每一行都是 [1,2k1] 的排列,所以可以直接求和,对于红色部分的两块多余部分,我们发现看他们的长边,都是 [2k1+1,2k] 的排列,他们也可以直接算出来,然后还剩下最后的绿色部分,由于我们前面补出的是一个正方形,所以绿色部分肯定在主对角线上,所以他左上角的值是 1,这样就可以继续向下递归求解这个小矩形的答案。

类似的,假设这个点在左下角或者右上角,那么他就只剩向左/上的红色部分,这个跟上面一致是可以算出来的,然后在递归小矩形的答案,但是由于他不在主对角线上,所以他的值会有一定偏移量,其实就是 2k1,递归时也要加上。

假设这个点在左上角,就是当前区间取大了,还可以取到更小的正好包含这个点的区间,所以令 k 缩小即可。

代码很好写,注意取模。

submission

P1169

跟上一场模拟赛 T4 一样的 trick 啊,悬线法 dp,解决二维 dp 中的某些求矩形的问题。

以本题为例,我们要求一个最大的 01 交错的矩形和正方形,直接做肯定是不好搞的,包括什么二分答案之类的,因为你不好写 check,而暴力 check 是 O(n2) 的,肯定爆炸。

考虑一种不一样的 dp 方式,定义 fi,j 表示点 (i,j) 向左最多到哪里是 01 交错的,同理 gi,j 表示向右的,然后定义 upi,j 表示这个点向上最多扩展几个,考虑如何转移。

显然,因为我们要找的是一个矩形,边长肯定是一定的,按照一段上下连续的 10 序列来看,要求这个序列中最小的 g 和最大的 f,就可以当作横边长了,然后连续段长就是纵高,就可以很好的维护面积了。

具体来说,先横向处理,当当前位置和前一个位置颜色不同时,

fi,j=fi,j1

gi,j=gi,j+1

之后,纵向处理,当这个点与上一行的颜色不同时,

fi,j=max{fi,jfi1,j}

gi,j=min{gi,jgi1,j}

upi,j=upi1,j+1

代码很好写,code

P9219

期末考完滚回来写题了,啥都不会了,菜的没谱。

感觉比较有意思的交互。

考虑保证有一个数不小于其他任何一个数的 2这个性质很重要,假设说,现在有三个点 x,y,z,已知 |xy|>|xz|>|yz|,说明此时 z 在中间,然后左边是 y,右边是 x,第一步 z 很好确定,那么 xy,我们发现,假设交换过来,y 在右,那么显然是不满足 2xy,因为向右走还有一个 z,感性理解一下,放到数轴上就好看了,比较懒,就不放图了。

有了这个结论之后,我们可以对 n 个数两两配对,那么答案点一定在差值最大的一组点里,这个同理也是可以得到的,然后我们还有两次判断的机会,对于 n 是偶数,直接找一个点判断位置关系就好了,对于 n 是奇数,我们还剩一个没有用的点,把这个点拿出来与最大点组判断位置关系就好了,判断次数刚好用完了。

code

P2258

感觉状态好一点了,虽然没有独立切掉。

暴力显然就是枚举行枚举列,因为确定了行数和列数,所以复杂度是 O(CnrCmc),无法通过。

考虑优化,我们只枚举一维,假设枚举行的选的情况,我们只需要确定一个列的选法的最大值,也就变成了一维的问题,此时设计 fi,j 表示第 i 列,已经选了 j 列的最小分数,枚举转移过来的上一列 k,这样我们就可以 O(rc) 的暴力计算分数,然后转移和前面的枚举是 O(Cnrm2) 的,所以复杂度 O(Cnrm2rc),可以通过。

code

P3874

01分数规划 + 树形dp。

先说一下分数规划吧,大概是要解决一个形似 aibi 的问题。

对于这个东西,我们直接二分答案,则有 aibi>mid,即 aimid×bi>0,也就是 (aimid×bi)>0,判断这个条件成立即可。

放到本题,基本与上述相同,每次二分答案平均值,将所有点的价值改为 vimid×wi,然后朴素树上背包即可,注意本题选择的一部分必须相连。

复杂度大概是 O((n3+nV)logn)

code

CF2040C

典型的注意力大题,我们考虑令 S(p) 如何最大,记 lii 左侧第一个小于它的数的位置,rii 右侧第一个小于它的数的位置,则这一个数的贡献为 i×(ili)×(rii),在这样一个排列中,我们肯定要令大数尽可能大,而他的最大贡献也就是 i×(ni+1),总的来看,这样构成的就是一个 1n 的排列,这也就是字典序最小的答案,反之从 n1 的排列就是最大的答案。

假设我们向空序列中从小到大填数,肯定是把当前这个数放到中间剩余空位的最左/最右才能使结果最优。说一下为什么最右也能最优,我们称最小答案 1n 的排列为原始序列,那么向右填数可以认为把原始序列中后面大数的区间向前平移,使得答案不变,所以,只要按照最左最右填数答案就是不会变的。因此,我们需要在每一个数的位置决策放在最左或最右,而最后一个数是不用决策的,所以序列情况数有 2n1 种,无解判断 k>2n1 即可。然后分析放左/右的情况变化,假设当前在 i 位置,那么在这个位置没有填入时情况数是 2ni 种,填在左侧之后,显然字典序是要比填右要小的,所以此时他所在的情况数区间就是 [1,2ni1],反之,填右的方案就是 (2ni1,2ni],类似线段树上决策,每次向右走减去 2ni1 即可。

Submisson

CF2013E

没切掉 *2200,想了一会感觉没问题交上去 WA on #3,发现考虑少了。

最开始考虑的是 gcd(a1,a2,...,an) 肯定是最小的,于是要尽快的令前缀 gcd 达到这个最小值,再进一步就很好想到把最小值放到第一个,考虑这个结论为什么是对的,假设此时的 gcd(a1,a2,..,an)=1,换成其他值也是同理的,此时有 a<b<c,我们先证明 a+gcd(a,b)b,首先有 gcd(a,b)=gcd(a,ba)=gcd(b,ba)(ba),所以 a+gcd(a,b)a+(ba)b,结论得证,此时我们假设 gcd(b,c)=1,有 a+gcd(a,b)<b+gcd(b,c)a+gcd(a,b)<b+gcd(a,b),所以把最小值放在第一个一定会使总值最小。

之后我们要选择第二个值,其实可以把 2n 位置的数全部变成 gcd(a1,ai) 即可,然后把此时的最小值放到第二个,证明同上,一定会使总值最小,所以依次这样放即可,可是时间复杂度看起来貌似是 O(n2) 的。

再仔细分析,令全部数 gcdk,前缀 gcd 最小值为 a,当 ak,后面的数每次取 gcd 时,值必定会减少至少一半,因为 a 最小的因数为 2,除非是 ai=a,而这样的情况会被放到序列最后,不会被纳入决策,或者令后面一段全部都是 ai=a,那就不符合 ak 的前提了,所以每个数至少被减少一半,复杂度实际为 O(nlogV)

Submisson

P11126

显然是放到值域上 dp,由于一个点的方案只跟上一个和上上个有关,所以我们可以设计 fi,j,k 表示第 i 个位置 i1 剩了 j 个,k1 剩了 k 个的方案数。

ci 表示 i 的数量,把两个分组方式分开转移,我们钦定每一次的 k 不需要再进行自减,那么有三个数的分组方式 fi+1,cik,jkfi,j,k,自减的就只有 j,发现这样也满足了前面的假定,fi,j3,kfi,j,k,就基本做完了,这样复杂度是 O(m3) 吗?分析一下,我们令 cimax(ci,ci1),那么 cici1ci2(ci)24m2,所以复杂度是正确的,O(m2)

code

P4215

好题,我们考虑类似李超树的分割方式,将所有答案区间放到线段树上,记录每个区间的拆分个数,做单点修改时向上 pushup 判断这个区间是否已空,如果已空,那么清除这个区间的所有答案下标即可,具体实现就是线段树每个节点开 vector,复杂度 O(nlogn+mlogn)

code

CF2063E

草,分析对了大部分手贱拆了个式子做不了了。

考虑拆式子,|dist(u,lca)dist(v,lca)|<k<dist(u,lca)+dist(v,lca),就是求 k 的取值数量,即 dist(u,lca)+dist(v,lca)|dist(u,lca)dist(v,lca)|1=du+dv+2dlca|dudv|1,分成三个部分分析,最后一个 1 显然有 n×(n1) 个,|dudv| 将其看做一个数列问题,按深度排序之后算正负贡献,dudv+2dlca 前面两项的数量显然是 n×(n1)lca 的数量就是普通的子树计数,注意当 lcau,v 重合时 1 的贡献不存在,加回来就好了。

Submission

等我再研究一下启发式合并做法。

P11829

构造还是做的太少了,开刷蓝题吧。

由性质入手,考虑当图中存在至少三个连通块时做法显然,而对于两个连通块,一个点数少的用一个颜色,另外剩一个大的随便取一个点就好了。

当图中只有一个连通块时,发现题目特别说明了只有 2n4 条边,注意到生成树有 n1 条边,在树上,我们先把所有点染成一个色,每一条额外边连接的两个点必须是不同颜色的,那么把每条边两个端点合并,因为只有 n3 条额外边,所有会剩下 3 个集合没有合并,这三个集合染三个颜色就做完了,好构造。

code

P11818

头一回写交互,这题倒是不难。

考虑到 0 的特殊性质,只要找到了 0 那么我们自然可以逐个找到 1,我们先随机抓一个数出来,把他跟所有数询问一遍,显然,如果当前数是 1,那么答案全是 1,如果是 0,那么答案是 [1,n1] 的排列,这两种直接判掉就好了。

否则,得到的答案中最大的数就是当前数的原始值(因为存在 0),我们把答案为最大数的位置都取出来,显然他们要么是 0 要么是这个数的倍数,对这些数再重复上述操作,能够发现,取出来的数可能为 0,那么操作完只会剩下 0 和另一个最大数,反过来,如果我们取了最大值,那么剩下的也会是 0 和最大值,所以我们并不能确定 0 的位置,每一次也不能删除我们一开始取来使用的数字。

经过很多轮这样的做法后,我们就会剩下不超过 2 个数,剩下一个的话显然就是 0,对于剩 2 个数,我们并不关系哪个是 0,只要找 1 就好了,将他们与我们第一次操作剔除的数进行询问,如果与第一个数得到的答案不是 1,那么当前数就肯定不是 1,否则再与第二个数询问,如果为 1,那么当前数显然为 1(因为 0),否则第二个数就肯定是 0,直接拿第二个数继续做就好了。

分析一下询问次数,最开始我们需要 n 次询问,后面每一次的最坏情况是询问到 2 的倍数,每次只能剔除一半的数,最后一步进行的询问数就是最开始剔除的数的个数,也就是 n2 次,所以最坏询问次数 n2+i=0log2nn2i5n2,可以通过。

code

posted @   Wei_Han  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示