The Tiny Summary

The Tiny summary

—— 最近做的没那么难但是又没那么简单的有的切掉了有的又被吊打了的题

CF1705D

有两个长度为 n 的 01 串 st。你可以在 s 上做一些操作:

  • i=2n1 中选一个,满足 si1si+1
  • 反转 si,即若 si=0,则令 si=1,反之同理。

n2×105

解法:一步至关重要的转化:

我们考虑这个操作究竟能干什么。
我们可以发现,进行一次操作可以 使 01 分界线移动 1,不会改变 01 的段数。
我们可以发现,操作本质上是将一个全为 1 的极大子串增长或缩短,但是两个子串不能合并,当然也不能调换位置顺序。

本质一次操作上是一个极长1 子串向左右扩展/收缩一位,但相邻两个子串不能相交。

注意 a1b1anbn 直接判无解。剩下扫一遍判断即可。

CF1699C

给定一个 0n1 的排列 a。定义 0 n1 的排列 ba 相似,当且仅当 1lrn,有 MEXi=lrai=MEXi=lrbi。求与 a 相似的排列个数(mod(109+7))。

注:一个数列的 MEX 表示没有出现在数列中的最小自然数,如 MEX([1,2,3,4,5])=0MEX([0,1,2,4,5])=3

多测,t1041n1050ai<n


(自己猜的结论)

设数 i 在原数列中的位置为 pos[i]
首先 0 的位置显然不能改变的,那么令 l=r=pos[0]
然后从 1n1 依次考虑每个数。若 i 的位置(下标)在 [l,r] 的范围之外,就令 l=min(l,pos[i]),r=max(r,pos[i])(相当于扩展),否则 Ans(初始为 1)乘上 ( 下标范围 [l,r]i 的数的个数 )

CF1709C

有个合法括号序列,部分字符被 ? 替换了,问是否存在唯一的一种? 的方案,使得括号序列合法,即判断填 ? 使得括号序列合法的方案数是否等于 1。存在唯一方案输出 YES,方案不唯一输出 NO

序列长度 n2×105,测试点数 T5×104


(毒瘤死我了)

貌似如果答案是 NO,那么一定存在两种方案,是的两者交换一对括号就可以互相转化。

那么我们先尽量填 (,剩下填 )。这样的括号序列的前缀和是最大的((1,   )1)。

然后交换一对括号给前缀和带来的影响是使得 [l,r) 的区间内的前缀和的值 2

若有的地方减成负数就不行了,然而我们选择最后一个 ? 处填的 '(' 和第一个 ? 处填的 ) 交换,因为如果交换这两个都不能产生新的合法解,那其他的显然是不行的qwq

貌似第一篇题解的做法更高级

CF1709E

你有一棵无根树,点数为 n,每个点有个点权 au,定义一条路径 P(u,v) 的权值为经过的所有点的点权的异或和。定义一棵树是合法的,当且仅当树上所有简单路径(只经过每个点一次的路径)的的权值都不为 0。你可以对权值进行修改,可以改成任意正整数,问最少修改多少次才能让这棵树合法。输出最小修改次数。

n2×105,ai230

zblzbl

第一步转化,设 du1u 的路径上的点权异或和,那么,一条路径异或和为 0dxdydLCA(x,y)=0

观察到「可以改成任意正整数」,那么我们其实可以随便改。如果我们将 u 的权值改成一个奇奇怪怪的数(MarkDown根本想不到),例如 2u+114514,这样保证了对于一个被改权值的点,不可能有一条在其子树内且经过它的边的边权异或和为 0(显然不可能了),且这些点的奇怪的权值两两不同。相当于对于来自两颗不同子树的两点不可能产生权值为 0 的路径了。

那我们接着考虑哪些点是需要改的。照这样想的话,改的点深度越大越优。

如何证明这一定能找到最优解?首先,如果存在两条有交集的路径 A,B,假设路径 A 两端点的 lca (以下简称路径 Alca)深度更大,在一番讨论后,我们发现,路径 Alca 一定落在 B 上,否则两个路径的交点就会有两个父亲,这显然不可能。有了这个结论以及上面的分析,我们会发现修改一个路径的 lca 一定是最优的,因为这样最有可能同时去掉最多异或值为 0 的路径,同时又因为我们从小到大枚举 lca 如果我们发现以当前节点为 lca 的路径出现了异或值为零的路径,我们就必须修改这个节点,因为如果路径上已经有节点被修改了,我们在遍历子树中节点时已经将所有需要修改的都修改了,还是使它权值为零,所以我们必须修改这个节点,因此,这样做是最优的。

然后对每个节点开一个 set 维护可能的 d 值,设现有集合为 S,该儿子的集合为 T,则枚举 T 中的所有元素。设当前枚举元素为 Ti,在 S 中查找是否存在 artTi
,若存在,则子树中一定存在两个点 u,v 满足 dudvart=0。因此一定要改变 art。同时若改变了一个节点的值,直接将该节点的 set 清空,因为改了之后一定不会产生节点为该节点子树内的非法路径了。

CF1689C

给定一棵以1 号节点为根的二叉树,总节点个数为 n

现在 1 号节点感染了病毒,病毒每一回合都会去感染与该节点直接相连的节点,而你在这一回合里可以选择删除任意一个没有被病毒感染(尚未被删除)的点,这样就断开了它与其直接相连的点得关系.

询问最多可以有多少不被病毒感染的点,被删除的点不算做不被病毒感染的点


树形 dp。因为是一颗二叉树,那么最后感染的节点肯定形成一条链。

一开始没想到 dp 还能这么玩 QAQ,因为这个状态是假设已经感染到了该点的,说实话有点奇怪

f[i] 表示若感染到 i 那么子树内最多能救多少节点
i 节点只有一个儿子那么直接堵住即可,相当于 dp 边界。
枚举堵哪一个儿子,按部就班 dp 即可。

CF1707A

做了 1:30


哆来咪·苏伊特参加了 n 场比赛。 比赛 i 只能在第 i 天进行。比赛 i 的难度为 ai。最初,哆来咪的 IQ 为 q 。 在第 i 天,哆来咪将选择是否参加比赛 i。只有当她当前的 IQ 大于 0 时,她才能参加比赛。

如果哆来咪选择在第 i 天参加比赛 i,则会发生以下情况:

  • 如果 ai>q,哆来咪会觉得自己不够聪明,所以 q 将会减 1
  • 否则,什么都不会改变。

如果她选择不参加比赛,一切都不会改变。哆来咪想参加尽可能多的比赛。请给哆来咪一个解决方案。


尝试了很多思路,想过反悔贪心但是不太行(要这玩意干嘛),O(n2)dp 很显然但是会 TLE,最后又想了一个二分的思路。

大概是这样:二分最后的智商,对于每一个最终智商,从后往前考虑每一场比赛,若 ainow 则直接碾压,若 ai=now+1 则不能参加(因为如果参加了就不合法了),若 ai>now+1 而且 now<m 就参加并且将智商提高 1,否则 now 已经达到上限 m,无法参加。这个贪心是几乎正确的,因为同样掉 1 的智商,在后面掉智商(从后往前考虑就是智商提升的越靠前)一定比在前面优。

于是按照这样的便利顺序提高智商。若最后 now=m,说明当前二分的最后智商值大了,否则 now<m 说明当前二分的值小了。

第一发调挂了,然后改了亿下,觉得没问题了,交了第二发,结果 test case 2 都不给过了吗 QAQ

于是拿出拍子开始拍,拍了大概四五百组小样例(说明这个解法离正解不远了)终于发现 WA 了。

1
14 5
0 11 10 0 12 3 10 12 3 0 12 0 3 1 

这组样例中,最后智商 lst=0 时(check 是没问题的)参加的最大比赛场数是 10,而 lst=1 时答案为 11。所以我们的单次 check 是没问题的,问题在于我们二分的东西不是完全单调的。原因是:

ai=now+1 则不能参加(因为如果参加了就不合法了)

而这组样例非常巧,最后一个数恰好是 1,导致带入 0 计算时发生单调性的错误。但是这种不单调的范围肯定非常小,因为只有 ai=now+1 才会有。

所以在 check 的时候加上这样一句话:

	for(int i = 1; i < 5 && mid + i <= R; ++i) chk(mid + i);

就过了。

有点玄学骗分的意味了

所以对拍这个东西真的非常强大呢 qwq


然后看了题解发现自己真实太菜了啊

主流做法是二分开始扣智商的地方,唯一和我的做法比较相近的是直接贪心的QAQ要什么二分啊

CF1693B

t 组数据,每组给定一个 n 个结点的树, 根为 1 ,给定 2,3,,n 的父结点 p2,p3,,pn 。再给出每个点权值 ai 的范围 [li,ri]

初始每个点的权值均为 0 。每次操作可以选择从 1 开始的树上路径 b1,b2,,bk (不一定要在叶子处结束),将 abi 加上 ci ,其中 {ci} 是一个 非负单调非减整数 数列。

问至少多少次操作,可以令所有点点权均在 [li,ri] 范围内。

1t1000,2n2×105,n2×105,1pi<i,1liri109


因为以前做过类似处理方法的题,所以做的相对轻松。

首先叶子节点(如果非 0)是一定要产生贡献的,那么我们考虑将一堆子节点的贡献“上传”至父节点,具体的:

    if(sum > R[u]) return R[u];
    else if(L[u] <= sum && sum <= R[u]) return sum;
    else if(sum < L[u]) { ++ans; return R[u]; }

这样贪心为什么是对的呢?当时我也没多想,后来大概想了一下:我们将子节点的最大的值放到一起讨论(相当于多个单调不增的序列合并一下),而在越浅的地方新开序列,能够以更大的初值往上计算贡献。

第一篇题解是树形 dp,我的做法的证明可以看后面的两篇题解。

因为多组询问忘记初始化vector图而浪费了20min

CF1693C

AmShZ已经从伊朗前往意大利参加托姆·约克音乐会。意大利有 n 座城市,编号为 1 ~ nm 条定向道路编号为 1 ~ m (2n2105,1m2105) 。起初,Keshi位于1号城市,他想去AmShZ在 n 市的家。由于Keshi不知道意大利地图,AmShZ要帮助他尽快见到自己。

在每天开始时,AmShZ可以向Keshi发送以下两条消息之一:

1.AmShZ将一条道路的编号作为阻塞道路发送给Keshi。然后,Keshi会明白,他永远不应该走这条路,他将留在他目前的城市的一天。

2.AmShZ告诉Keshi离开。然后,Keshi将随机选择一个可以从当前城市到达的城市,并搬到那里。(如果从 A 市到 B 市有一条出口道路尚未堵塞,则可以从 A 市到达 B 市)。如果没有这样的城市,Keshi将留在他现在的城市。注意,AmShZ总是知道Keshi的当前位置。

AmShZ和Keshi希望找到尽可能小的整数 d ,使得他们可以确保在最多 d 天之后彼此见面。帮助他们找到 d


分析一下,题目的“随机一条出边”其实就是“最差的一条出边”。然后发现图中有环的话是肯定不行的,因为会一直绕。砍掉环之后原图就会变成一个 DAG,在上边建反图跑 dp 即可,但问题是怎么看这些环呢?于是就越想越奇怪,发现好像不太行的样子......

止步于此。

迫不得已打开题解,发现这题是一个我根本不会的dijkstra

貌似需要再学一遍 dijkstra

CF1687B

给定一个图,你每次询问可以控制每条边通断,并获得最大生成森林答案,不超过 2m 次询问,需要求全图的最小生成森林。


考虑模拟 kruskal 的过程来求最小生成树,即:

首先我们可以用 m 次询问求出每条边的边权, 再按边权从小到大的顺序尝试加入每条边。

对于当前考虑的边,设其权为 w 且连接了 u,v, 则我们需要判断,

是否存在一条左右端点分别为 u,v 的链,满足这条链上所有边的权值都小于 w

如果不存在,则等价于当前边不在最小生成树中, 而这个条件的判定,我们可以用两次询问做到。

具体的,我们先查询出:保留所有边权不超过 w 的边的最大生成树的边权和 x

我们再查询出:保留所有边权小于 w 的边并查询出最大生成树的边权和 x,那么 xx=wx−x 就等价于不存在一条满足上面要求的链, 原因是所有边的权值都是正的。

注意到某次查询出的 x 实际上就是上一次查询出的 x, 所以一共用 2m 次查询,就能求出最小生成树的权值和。

CF1687C

给你两个长度均为 n 的序列 A,Bm 个区间。对于一个区间 [l,r] 若当前序列的 i=lrAi=i=lrBi,那么就可以将 A[l,r] 对应赋值为 B[l,r](即 AlBl,Al+1Bl+1,...,ArBr)。 问能不能将 A 最终变成 B。多测,n,m2×105


这是个神奇的题。当时想到可以建立 BFS 框架但实在想不到并查集。。。因为不太熟。

换一下式子,先将 a,b 变成对应的前缀和,那么能够操作即为 aral1=brbl1  arbr=al1bl1,所以定义新的数组 ci=aibi,若 cl=cr=0 即是有意义的操作,能够将 c[lr] 推平为 0

能够发现是原来一下满足条件的区间然后带动其他有交集的区间在扩展,这里能够想到 BFS 遍历。

其实这样要做很多没用的更新,所以我们用 DSU 维护一个点右边最近的没覆盖的点是什么,然后跑 BFS 更新即可。

题解:

首先将 ai 减去 bi,这样就转化为 b 序列全零的问题了,也就是说:
给一些区间,当区间内和为 0 的时候可以将区间所有数全部置为 0,求是否可以将整个序列全部变为 0
但是这样还是不好搞,因为区间之间的操作顺序影响结果。
由于是区间和之类的问题,我们想到前缀和。
a 的前缀和序列为 c0(=0),c1,c2,,cn,则问题转化为:
给一些区间 (l,r](左开右闭),当 cl=cr 的时候可以将区间内所有 ci 全部置为 cl(=cr),求是否可以将整个序列全部变为 0
我们发现若 cl=cr0,这样操作的话是没有意义的,因为操作完后不会新增 c 序列中的 0
紧接着,发现这些区间设为 0 的操作顺序是无关的。
所以我们存一个队列,表示当前有哪些区间的 cl=cr=0,我们依次操作,然后判断是否有新增的这样的区间,把她们加进队列。
具体地,对每一个位置开 vector 表示这个位置有哪些区间的端点。同时开序列上的并查集,可以 O(α(n)) 跳过连续的 0 区间。由于每一个位置变为 0 后不会再变回非 0,所以时间复杂度是 O(m+nα(n))
最后判断一下 c 是否全零即可。

CF1684D

这里有 n 个陷阱,你需要按照给出的顺序穿过这些陷阱,每个陷阱将会对你造成 ai 的伤害

你有至多 k 次机会跳过这些陷阱,可以避免你所跳过的陷阱给你造成的伤害,不过接下来的所有陷阱都会给你多造成 1 点伤害

跳过陷阱所造成的额外伤害会叠加,如果你当前已经跳过了 3 个陷阱,接下来的陷阱给你造成的伤害将会是 ai+3

现在需要你求出受到的最小伤害


比较简单的贪心,但是写错了一个地方 + 中途打断施法然后就挂了。

跳过一个陷阱,能躲掉 ai 的伤害,又带来 ni 的伤害,相当于躲掉了 ain+i 的伤害,排个序取前 k 大的伤害躲掉即可。(具体证明看题解)

CF1684E

给你一个大小为 n 的数组 a,保证数组内元素非负,你可以执行以下操作 k 次:

在一次操作中将数组内任意一个数字改为任何一个非负整数。

现在定义这个数组的成本为 DIFF(a)MEX(a),其中 DIFF(a) 为a数组内元素去重后的数量, MEX(a) 为数组中未出现的元素中最小的元素,

现在给你数组 a,求能实现的最小成本。


大概猜到了但是不会调啊

有些性质很明显:

  • k 次机会一定都得用,因为用了答案不会劣。
  • 使用修改一定改成当前的 MEX,因为其他的修改没意义,即使后面有意义了也可以通过调换操作顺序变成前一种。
  • 那按这样最优的策略修改,最终的 MEX 值是固定的。
  • 考虑怎么让 DIFF 最小,把剩下的 >MEX 的数以及它们的个数统计一下然后贪心地优先选少的修改。

怎么题解都是线段树啊

CF1684F

给定长度为 n 的序列 a,以及 m 个数对 (li,ri)
你可以进行下列操作至多一次:

  • 选择序列 a 的一个子段,并将其中的每个元素的值都改成任意整数。

你需要保证执行完操作之后,对于每个整数 i(1im),都有 a[li,ri] 中所有元素互不相同。
你需要最小化操作时选择的子段的长度,并求出这个长度的最小值。
特别的如果没有必要进行操作,答案为 0


QAQ 太菜了啊

这题一看上去那简直是非常的可做,然后自己模了半天发现一开始自己就错了。

首先套路性地求 pre[i] 表示 ai 这个值上一次出现的位置。

接着求 lim[i] 表示包含位置 i 的所有区间中 L 值最小的那个区间的 L 值。

那么这个限制就是 ipre[i]<lim[i]

考虑以每一个位置为左端点的时候区间求右端点及区间最短长度,那么这个东西的答案是不降的,就是说可以双指针。

维护一个变量 cur,表示有多少对 pre[i]lim[i],那么合法即 cur=0。开(去重后元素个数)个 set 维护每一种值的出现地方的下标,这样就可以动态查询 pre,nxt 值了。

参照了第 4 篇题解。有些细节仍不是很理解。

CF1648B

题意:给定一个数组 a,我们称该数组完整需要满足:若数组 a 中存在两数 x,y, 使 yx(x,y 可以是同一个数),则xy也必须在数组a 中 , 现需要判断数组 a 是否完整 。

T104,n106,c106 , 其中 T 为数据组数 ,  n a 的元素个数,满足a 中元素c


发现这个 c 很小,只有 106 ,所以可以将每个元素是否出现都存起来。

枚举倍数,若 ab=k ,则 a 一定在 [b×k,b×(k+1)1] 这个范围内。

然后对每个元素判断一下数组中是否有在这个区间的就行了。

坑点: 不要把整个数组清空,否则时间会爆炸。

CF1641B

T 组数据,每组数据给你一个长度为 n 的序列,满足 n500n2250000。你要完成一个任务:就是把整个序列分成几段。每一段都必须长度为偶数并且前半段和后半段要完全相同。为了让你完成这个任务,你可以执行这样一个操作:在当前的p 个数后面加 两个 c。位置 p (合法范围内) 和数值 c 任意。这个操作次数不能超过 2×n2 次。对于每组数据,如果无解只需要输出 -1

如果有解,输出方案,格式见下:

第一行你需要输出一个 q,表示操作了几次。
接下来 q 行,每行输出两个数 p,c ,表示在当前序列的第 p 个数后面添加两个数值为 c 的数。注意,p 应该满足 0pm,其中 m 是当前序列的长度。
接下来一行你需要输出一个 d,表示将整个序列划分成了 d 段。
接下来一行,输出一个长度为 d 的序列 t1,t2,...,td ,表示从前向后划分的每一段的长度。 显然需要满足的是 d,ti1
设最后序列 a 的长度为 m=n+2×q 。则需满足 m=i=1dti
划分的每一段都要满足条件,即对于 1id,对应序列上的区间 [l,r] 需满足前半段和后半段完全相同,其中 l=j=1i1tj+1,r=l+ti1

可能有多种方案,你只需要输出其中一种。


智慧构造题。

对于一个段,找到第一个数字的匹配处,然后暴力把中间的一段复制一遍,然后就相当于把这一段反转再接上后面的一段。至于这样为什么一定能匹配上? (我也不知道)

CF1641C

对于一排病人, 医生可以做三种操作:

  1. 确定 l, r, 0 表示第 lr 个人中没有病人
  2. 确定 l, r, 1 表示第 lr 个人中至少有一个病人生病
  3. 询问第 j 个病人有没有生病

对于每一个操作 3 , 可以确定生病输出 YES , 可以确定不生病输出 NO , 否则输出 N/A。保证操作均合法,即至少存在一种方式满足所有的操作信息。


分析性质 × 数据结构

关键结论是一个人有病 被包含在一段其他元素确认无病的“至少一个有病”的区间内。考虑维护,即一个人左右各有一段无病,且存在一个左右端点均在左右“无病区间”内的“有病区间”,否则直接判N/A。用 set 维护当前不确定的人,线段树维护以 l 为左端点的“有病”区间的右端点最小值。设当前询问是 x,那么我们找到前一个不确定有没有病和后一个的位置,记为 l,r,然后在线段树上查询 [l+1,x] 段的最小值是否 <r 即可(此时 [l+1,x1] 的人一定没病)。

题解区有个 DSU 的做法挺妙的但是不太懂......

posted @   badFlamesへ  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示