Codeforces VP与做题记录
一些早期vp在这里。
开始复健!一天一场。 主要打 div2,现在水平不太适合打 div1 [捂脸].
欢迎监督我!
绿色是赛时切掉。 蓝色是赛后独立做出。红色是看了题解。难度 2000 以下的题除非没做出来是不会管的,3000 以上的看心情做。
很好的题或者对 OI 内容有很强联系或者较大启发的题会标 。
编号排序,时间顺序无关。
目前完成了 CF Round 857(CF1802)~CF Round 890(CF1856) 中的所有 div2(大多数在上面的洛谷博客里懒得搬了)。
感觉刷 div2 收获不是特别大。接下来的安排是稍微休息一下学习一下相关知识然后开始刷 。
CF1834
date 23/8/7
很简单的一场,和后面那场是两个极端了。
简单题,赛时把 LCM 和 std::lcm 用混了。
序列的区间 和区间 都只会有 种,因为向集合里加入一个数的话两者都是成倍增长或缩小的。
直接枚举左端点二分右端点下一个改变的位置可以做到 能过。
右端点是不减的,维护 个指针可以做到 。
答案的一个显然下界是 ,因为这些数只能通过重置小车回到之前的位置。尝试向下届构造答案。
因为是排列排序问题,所以肯定先把置换环拿出来,如果我们能对于每个置换环在其 次排好序那么分别解决每个置换环即可。
对于每个置换环,每次选择最小的位置开始往后挪,每次换到下一个就交换,遇到第一个 就停止交换然后重置回来放过去即可。
于是就变成了对于排列维护 ,支持全局 shift 和 reverse。
最开始的想法是直接维护这个序列的全局平移量和是否反转,然后就变成了一个形如二维数点的东西(某个区间里 的个数),比较麻烦但可以做。
写着写着发现序列总共只有 种不同的状态,由平移量和是否 reverse 决定,reverse 是平凡的,只需要同时维护相反的序列。
可以考虑每个数对每个平移量的贡献, 仅当起始点在某一段里,使得这个数里起始点真正的距离 ,小于这个值 。所以直接对平移量在某个区间( 是 的环上的区间所以可能是一个前缀和一个后缀)造成 的贡献即可。
复杂度线性。
这启示我们思考:
在过程看起来很复杂的题,考虑答案是否能达到下界?如果不能什么时候不能?
在各种修改下,本质不同的状态有哪些?每个元素在可以对哪些状态下的询问产生贡献?
CF1836
date 23/8/4~6
红红火火了属于是,这场强度很高,wtcl。
我的做法因为实现太笨 MLE 了,如果开 512M 可能能过,简单阐述一下。
枚举每个中奖位置,只需要比离着个位置第 近的位置近就行了,可以受到贡献的位置是一个区间。
又因为离中奖位置第 近的位置只会变化 次,所以求出 段位置,每段的 近是相同的,形成的贡献区间就是若干段左端点或右端点相同而另一端点依次 的区间,所以考虑维每个位置关于 的系数即可。使用差分数组完成静态区间加。
离散化等实现极为答辩。空间常数高达 还要 int128,过不了一点。
题解做法很聪明:考虑买的位置和其它人的位置的相对关系,当中奖彩票在这个位置左边时只需要相较于左侧第 个更接近我买的位置,右侧同理只需要比右侧第 更近即可,所以可行的中奖位置也是一个区间,且这个区间的长度只和位置奇偶性相关(下取整产生的差距),所以 check 左边第一个和第二个即可。边界情况左右不一定能够凑满了 个,所以可能会随着位置的变化奇偶分别构成一次函数,需要 check 两侧的两个。
并不是非得考虑贡献的啊啊啊啊闹贪!
如果很多时候做法很复杂的时候考虑更换一种统计的方式(对于 可行的 ,对于 可行的 )。
为啥我啥都不会。
首先先变成前缀异或,然后变成选择两个二元组 使得 。
确定性做法:
因为值域是平方于序列长度的,考虑 meet-in-the-middle,将数拆成前后两部分,我们先取所有前 位为 的二元组,位置共有 ,因为鸽巢原理,至少存在 组左端点和右端点分别互不相同的这样的二元组。
再用一次鸽巢原理,后 为共 种, 种必然碰撞。
随机化做法:
随机样本空间大小是 的,那么随机样本第一次发生碰撞的期望次数是 个。
直接随机选线段就行。
很好的题目!
互相到达首先在同一个强连通分量里面,直接划分成若干强连通分量做。
首先 意味着我们可以绕完强连通分量内部的所有长度的环每个至少 次,这可以凑成的长度一定是所有环长最大公因数 的倍数(裴蜀定理),且当长度大于 时可以通过调整凑出所有 的倍数。
接下来要求所有环长的 。
若环长为 的倍数:
那么这个图一定是一种 意义下的权值传递关系(所有环的权值为 ),所有边 都满足 ,否则可以推出一定存在一个环的权值非 。
这是环长是 的倍数的充分必要条件。
充分性显然,必要性可以根据任意选择一点跑一棵外向树构造出来,并且存在外向树方案的构造也是充分必要条件。
所以我们直接跑一棵外向树,构造一组权值,然后对于所有 ,所有环长都满足是 的因数,否则 就不成立。
环长的 一定是所有 的因数,这是必要的。
而我们给出了构造,这也是充分的。
CF1847
date 23/8/9
一点也不 OI,/fn。
按顺序决定每个字母的优先级,然后把所有 往尽可能优先的位置放。
令 的个数为 ,答案就是优先级前 小的位置中 的个数。
最开始把这个题看成了修改 使得字典序最小,想到了一些根号重构做法考虑点对线段的贡献和通过前缀和重构,挺有意思的。
很没思路的题。
考虑知道三角形两边如果可以组成三角那么一定可以算出另一条边长度。
我们的策略是具体求出两个 或 或 ,然后对于用它们去询问所有数求出答案。
如何求出两个 或 或 ? 和 面积是相同的,如果要具体处理每种三角形很麻烦。
等边三角形是好判断的,所以我们考虑求出三个相同的,而值域是 ,所以任意 个中一定有 个相同数。我们直接暴力询问 次一定可以找出来。
如果相同的是 ,直接做即可。
如果相同的是 ,则可以求出每个数是否为 ,直到找出 个非 的数后停下,则一定存在 个相同的非 数,可以直接把剩下的数都解决掉,之前判断为 的数不用扫,只有这 个数被扫了多于 遍。
如果找不出 个就再暴力一次。
不超过 次,细节比较多。
鸽巢原理看似简单。 但很多时在“发现若干个相同的时候最少要多少个”这种问题下并不是很好想到啊。
为什么没想到这么ez的问题啊。
因为贡献是 ,所以把 个数放在一层,考虑每层向下一层的贡献,还有每层第一个向最后一个的贡献。
首先画出来贡献关系的图,会发现在第 层。每个初始的 产生的贡献是往前的一个区间以及如果更新了 对 的贡献,就是两个区间。
然后我就莫名其妙开始想对于单个询问怎么做:
二分层,然后 check 就是 个区间 OR,查询全局max。
好了然后就卡在了计算每个点对一个区间的贡献然后二分这个位置,然后按位或这个东西又是很难从数的层面上去考虑的。
回过来看每个值,对他造成贡献的还是两个区间,且随着层数变大而变大。
因为按位或下去之后会 个不同的值。所以直接二分层数求出 个不同的值(只在意每个值第一个位置),然后在里面二分就行了。
我怎么这么笨。
睡个午觉再开一场。
CF1848
date 23/8/3
很 math,感觉含金量不高。
并没有什么含金量的题。
考虑 连边形成基环树。然后链上的部分直接进行 暴力。
环上的部分(,可以求出一个“大概期望圈数 ”,每圈消耗 步,带来 的变化量。
均值不等式得到当增加的收益与减少的收益相同时取最大值。
得到 。
真实圈数与这个圈数只差的步数是 的,因为超过 圈一定会不优(由上式)。
引出的一个值得思考的问题是对于一个任意权值的基环树多次询问?现在不太有思路。留着想下。
比较简单的解方程。
初始力量为 ,第 次位置为 。
用二次方程求根求 ,其中根号下的项为 。同时发现如果根号的结果为正奇数是 有解的充要条件。
令这个正奇数为 则有 ,解出来 。
这等价于将一个数分解为奇数 * 偶数的方案数,去掉所有 因子只能放在偶数,剩下的就是因数个数, 。
然后通过预处理质因数不难做到 。
适当的换元可以降低计算难度,别急。
典中典的感觉。
位置 进行 步对 贡献为 。
,卢卡斯定理。
考虑直接变化 次这样就只会影响两个位置 ,所以可以 求出变化 后的数组。
直接倍增,目前确定了答案的一个前缀,看这位能否填 只需要 check 后方能否填 即可,如果可以就尝试填 。
倍增如果可行的最小值不太好 check 可以 check 后一个位置。
CF 1855
date. 23/8/2~3
把数组全部变成正数或者负数做前后缀和就行了。
赛时卡在了 次修改如何优化了。
瓶颈在于把所有数变成正数或者负数,最开始的想法确实是少变多,但是可能出现的情况是少变多需要扩倍 次,这样才能造出绝对值够大的数,可能达到三十四次,但是此时选择变化另一边就不需要扩倍,所以权衡一下两边的次数选择较小的一侧。两侧扩倍消耗的次数之和是 ,修改另一类数消耗的次数之和是 ,所以两种方案的次数之和是 ,较小者必然 。
不要局限于如何优化单步。可能这种方案在某种情况不优,但是另外一部分会变优秀。权衡全局。
令 前缀和为 ,其中 。
分析一下发现我们只关心最终解锁的前缀的长度。因为我们获得的代价一定等于 ,累计打开的长度都是固定的。 接下来这个问题就比较类似于背包凑数了。
然后考虑按顺序决定加入或不加入每个数,基于背包来考虑。
表示前 个数能否凑成 。 转移就是 。
注意到 dp 是 Boolean 的,转移也是平移,使用 bitset 可以做到 。
令 。
考虑一组 ,如果是在两者之前的数向前移动碰上了 ,可以理解为它消失了,如果是 碰上之后的数可以理解为之后的数消失了。 所以这些相邻位置的组是互不影响的,只需要求出每组 ,追上后者的期望移动次数进行求和。
表示前者在 后者在 的期望次数,则答案为 。
只考虑这二者的移动:转移有 ,分别是前者移动或是后者移动。 边界为 。
观察问题之间是否真的相互影响了,这可以将问题拆成若干个较为平凡的子问题。
。(这种碰撞然后变成对方的思路好像经常用到?)
题意即使求出 所在基环树的大小。
对点集进行二分可以找到一个点的确切后继。
一个直接的做法是询问后继集合然后二分,消耗 9 次找出森林的形态。消耗 次,不能过。
另一个办法是先找到环上一个点,然后向外一层一层拓展,这样最坏的询问次数是 的,有点浪费。 考虑一次拓展多层。
询问的步数太长会让一些本身能走到环上的点走了太多步离开环上了,所以如果我们目前环上的连续段的长度是 ,我们可以询问 以将环上的点数扩倍,并可能带入一些不在环上但是在同一连通块内的点,消耗次数是 的,也不能过。
第二个办法的复杂度瓶颈主要在环上点较少的时候效率较低。所以考虑拼起来,用第一部分的 次的暴力解决,第二个部分对于环长为 的环,平均每个点的消耗次数为 ,当这个值小于 9 的时候,使用暴力会更加优秀。
先找到 个点,然后倍增,直至发现完整的环后查询剩余的点走 步是否会到达环或者环周围的点即可。
如何发现是否成为完整的环? 不在乎是否成为完整的环,就算是已经成为完整的环,保证点数仍至少倍增仍然可以保证询问次数的正确性,如果点数没有倍增,那么一定没有成为完整的环, 直接退出进行询问即可。
经过枚举发现值取 最优()是只需要扩倍四次的最小数,总询问次数不超过 。 最后一部分表示询问周围的点是否能到达环上。
牢记两个暴力阈值分治拼一起可能就是正解!!很多时候在值大的时候优秀的算法在值小的时候可以被暴力替代(你怎么练了那么多根号分治还是想不到!)。
所以多想几种不一样的 复杂度或许不对的 暴力对正解是有很大启发作用的。
CF1856
date 23/8/5~6
这场很简单啊,如果白天打可能能 AK。
不难。赛时写 E2 上头了没看。
区间逆序对对于最大值来说是个很复杂的信息,考虑简单化它:如果这个值比前面的某些值都大的话它一定不会和前面构成逆序对,如果比后面某些值都大那么一定都会构成逆序对。
一个一个检查逆序对的花费是 的,因为查询的代价是和规模的平方相关的,所以可以发现出题人想让我们实现的问题尽可能缩减问题规模大小,可以考虑使用分治将问题缩小到折半的规模。
找这个区加的最值:分别找到左右子区间的最值 ,然后比较二者的大小:只需要询问 是否相等即可。
代价分析是简单主定理。
手算一下常数不超过 。
这个 E2 真的差一 min 就写完了,难过。
考虑从上往下填在 LCA 处统计。对于可以在这个点形成两个点(不在同一个子树里),在这里形成一定不会更劣,放到子树里不一定能形成,而这也并不能使在这个点多统计一组。
由这个可以发现我们把一个子树内的值填成连续的一段一定是不劣的,所以接下来就是把子树分成两种,使得比它大的子树大小之和 和比他小的子树的大小之和 的乘积最大,因为均值不等式一定是在 差最小的时候取到最值所以就是要尽可能平均分成两个集合,直接背包可以做到 ,每个点对只会在 LCA 被统计。
在每一个点时做的操作就是“把儿子大小构成的数集合分成差尽可能小的两部分”。
接下来来解决 E2:
首先一个观察就是单个问题“把儿子大小构成的数集合分成差尽可能小的两部分”是一个 的背包可行性问题。没有 的做法,常见的做法有三种:
- 所以 的种类只有 种,直接做余数分类 。
- 将每种 的个数进行二进制拆分,然后
bitset
压位复杂度 ,常数很小。 - 多项式卷积,NTT 或 FFT 合并,,常数大。
令上方解决规模 单层问题的复杂度为 。
如果每层都解决一次这样的问题,复杂度仍然是 的,这最坏仍然可以达到 。
因为树 的构成是具有特殊性的,解决完这个问题后子问题的规模和这个问题的构成是密切相关的 (这显然弱于解决任意 次上面问题)。
又因为我们只是想尽可能平均分两个集合,所以当重儿子的 大于其它儿子的 之和时,一定会选择将重儿子放在一个集合中,所有轻儿子放在另一集合,所以只有重儿子的 小于目前 的一半时我们才会进行背包,而如果重儿子的 小于目前 的一半,然后所有子问题的规模都变成了原来的一半,所以最坏复杂度为 。
带入具体复杂度分析都是简单的主定理:
如果 ,。
如果 ,。
如果 ,。
第三种理论最优,但是在题目数据范围下使用第二种,最坏耗时约 300ms,可以轻松通过。
一个实现上的小问题是需要使用动态大小的 bitset
,可以选择手写或者提前开好所有大小为 的 bitset
,然后使用的时候选择最小的可用的。
CF1858
date 23/08/19
被我想复杂了:
考虑最后答案的零段和一段一定是两个不交的段,然后不妨变成一个前缀里面选择 段和一个后缀里面选择 段。
然后就让 表示前/后 个里面改 个,最长的 0/1 串,这个就直接取前/后缀 即可。
然后枚举分界点,对于每一个分界点要求出对于所有 , 的最值,就是一堆一次函数,静态,多次给出 求最值。这个可以求出凸包或者好写直接分治求。
然而并不用。不同分界点之间的问题没有本质不同,只需要对于所有 的 求出最大的 然后 地试一遍就像了。
为什么出这么 Ez 的题啊(恼)。
看到有撤回操作和删除末尾若干个每次改变的都是后缀,所以考虑建出操作树,离线,我们的操作相当于如下:
+ x
给目前点加一个儿子 。
- x
跳至 级祖先。
!
回到到达过的上一个节点。
?
查询到根路径上的颜色数。
然后就直接模拟地把树建出来,拿一个栈维护去过的点,用倍增跳 级祖先,最后遍历一遍树维护颜色出现次数求答案。
炫酷做法:
因为强制在线了,所以需要在线地对于每个点维护这个出现次数数组并需要继承父亲的数组。这个可以通过主席树完成,但是被卡空间了,对主席树做一些优化即可,如并不需要记录每个点是否有值,或着用 bitset
完成底层分块等可以卡过去。
线性做法(题解):
考虑其实这个操作树其实并没有必要建出来,可以使用“假装删除”的套路,维护每个前缀的答案,然后化末端添加为单点修改,然后撤回的时候改回去,直接做可以做到 ,发现如果发生更改一定是在序列末尾,把树状数组换成前缀和就是 的了。
CF中分段选做
主要做 2400 ~ 2800。时不时更新。有时候可能在做别的,闲了再做 CF。
如果犇犇里看到好题了或者看到别人发的题解的话会去做做看。
date 23/8/21
至少一条完全做不了,直接考虑容斥 表示编号只在 中的染色方案数,那么答案就是 。
分别考虑算:
。
相当于要求每条边至少有一个 ,即点覆盖计数,直接求是 的,可以映射到独立集计数 ,因为 ,可以用 ,具体就是把点分成两份,然后分别求出两边的独立集,然后枚举左边的独立集,求出没有连边的右部点,查询右侧某个点集内的独立集数,这个直接 FWT 就行。
相当于每条边两侧颜色相同,所以每个连通块要么全黑要么全白。
相当于二分图黑白染色数。判二分图后数连通块即可。
相当于连了边的点必须为 ,只有孤点能任意染色,其它确定。
仅当图没有边时为 。
时间复杂度 ,其中取 。
还能在给力一点。
观察前面求独立集的过程我们其实只 FWT 了右侧(判独立集,边集的并可以用加入 lowbit 优化到 )。
所以其实复杂度是 ,因为 的最优选择不会离 差太多,所以二者乘积看作定值 ,两边取等时最优为 。
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17603090.html,谢谢你的阅读或转载!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步