CFの题 Ⅲ
CF1647E
首先每次新增的人数是确定的,所以可以很快统计游戏进行的轮数。然后就可以倍增来找出每个位置最后存在的位置,然后就可以发现位置大概分成两类,有主的和无主的。有主的就是最后位置的数是原先十三个州中的一员,相同主的显然会构成一个集合,集合中需要满足有这个主并且其它元素大于这个主。到这一步就可以贪心了。某个集合第一次出现的元素一定选择这个主,因为这样可以保证字典序最小。然后剩下的数用 set 维护,二分找到大于主的最小的数,即可,复杂度线性对数。注意迭代器被删除之后就不能引用了,调了半个多小时。
CF1700E
不难但是我脑车了。显然的结论是一个图合法当且仅当任意前缀形成一个连续块,然后重要的一点是说这一条件可转化成任意一个不为 \(1\) 的点四周必然至少有一个数小于它,这样一来有些点是一定要换的(也就是不合法点以及其四联通的点,如果不合法点太多直接返回 \(-1\) 即可),而且这样的点不会太多(大概 \(20\) 个)。于是可以枚举另一个点是什么,然后检查受影响的点判断是否合法即可。
CF750E
用 \(f_{x,0/1/2/3/4}\) 代表目前最好的已经有了 \(\varnothing,2,20,201,2017\) 并且没有 \(2016\) 最少需要删除的数目。然后就可以列方程了。
用线段树维护区间积即可。然后有一个,出于看着方便的考虑,答案矩阵应该横着,不然由于适配性会出一些问题。
CF1039D
整体二分题。首先根据数论分块类似的道理,答案的数量不会特别多。而且由于这个数列具有显而易见的单调性,所以可以整体二分。然后 check 部分可以考虑贪心去做,对于每个点找出最长链和次长链,发现如果这两条链合起来可以拼成一个合法的链,那么贪心地拼起来,因为这样肯定最优(否则如果向上合并就只能丢弃次长链,看着就不太优秀);否则就向上传递最长链即可。有一些需要注意的地方,一个是为了卡常可以把所有点按 dfn 序存起来,就像 SAM 的那个技巧一样;然后就是二分的时候需要注意,如果最后分裂的区间是 \([wl,l]\) 和 \([l+1,wr]\) 的话,那么 \(l\) 的初始值应该是 \(wl-1\)。然后就没什么了。
CF1254D
学习了一个树剖的套路,大概是说有一棵无根树,每次操作某个点,具体内容为给这个点的所有子树加上或者搞点其它什么操作,最后单点查询,希望单 \(\log\)。方法是对于一次操作,父亲所在的子树和重儿子所在的子树单独处理,然后考虑一个点可能被哪些点贡献。显然产生贡献的点应该是询问点的父亲,而且询问点不在其重儿子内,直接重链剖分向上跳就可以了。具体到这道题,发现一个点会被产生贡献当且仅当点 \(r\) 不在那个点所在连通块中,其概率是 \(\dfrac{m-siz_x}{m}\),所以其权值的期望应该是 \(\dfrac{(m-siz_x)d}{m}\),记录即可。复杂度 \(O(N\log N)\)。
CF1764H
一道很妙的题目。贡献可以分成两类,一类是一直没有被覆盖到的地方,一类是左端点没有被覆盖过并且整个区间没有被完全覆盖。首先是第一个问题,考虑用 set 维护整个区间,每个区间维护其左右端点以及上一次被覆盖的时间,需要保持所有区间的并刚好是原区间。那么对于一个被当前节点覆盖的区间,这个区间没有被覆盖的时间是记录的时间加一到当前时间减一,然后同时会更新一些区间的时间,考虑分析一下复杂度,会发现每个操作只会用左右端点对集合中的区间进行切分,所以区间数量不会太多,所以复杂度是正确的。然后就可以得到形如 \((l,r,v)\) 的信息,表示一个询问 \((L,R)\) 如果满足 \(l\le L,R\le r\) 的话就会有 \(v\) 的贡献,然后扫描线维护就可以了。然后是考虑没有被完全覆盖的区间。一个区间本身被完全覆盖的时间记为 \(ti_x\),它左端点被完全覆盖的时间记为 \(last_x\),显然如果一个询问满足 \(L\le last_x\),那么这个区间是不会有贡献的。然后考虑什么时候这个区间会被完全覆盖,可以从后往前扫描一遍,更新就可以了。最后就是一堆扫描线,离线树状数组即可,复杂度线性对数。
Gym103687D
比较神秘的题目。首先发现对于每个左端点,右端点越向右延申,最后出来的期望越小,显然正确。所以用 \(f_x\) 代表以 \(x\) 为左端点时右端点最少挪动到哪里可以满足要求,最后的答案是 \(\sum\limits_{i=1}^mm+1-f_i\)。然后发现 \(f\) 显然也是具有单调性的,所以可以考虑整体二分。记当前的节点是 \((wl,wr,ql,qr)\),考虑如何计算 \(mid\) 的答案。为了节约时间,我们认为 \([wl,wr]\cup[ql,qr]\) 以外的物品价格已经固定了,所以已经加入到当前背包里了,于是只需要先把 \(mid\) 之前的物品加入进来,然后对其进行二分即可。二分的过程中动态地把已经确定价格的物品加入到背包中,最后再把问题拆分开来即可。有些细节,但只要牢记当前状态“除了两个区间并以外的物品都已经全部确定了价格并且加入到背包中了”这一定义就可以了。可以发现复杂度是 \(O(NL\log N)\),然后发现 new 是真挺好用的。
CF1778D
一道比较神奇的题目。记 \(f_x\) 为当前有 \(x\) 个错误的位置,要修正其中的一个错误需要的期望次数。考虑这一步的贡献,如果幸运地修正了错误,那么期望是 \(\frac{i}{n}\);如果增加了错误,那么就相当于是到了下一个状态,期望是 \(\frac{n-i}{n}(f_x+f_{x+1}+1)\)。化简可以得到 \(f_x=\dfrac{n+(n-i)f_{x+1}}{i}\),边界是 \(f_n=1\),复杂度是线性对数。
CF1768F
一道非常巧妙的题目。
题意是求 \(f_x=\min\limits_{y<x}\{\min\limits_{y\le i\le x}a_i\times(y-x)^2+f_y\}\),数据范围 \(4\times 10^5\)。
有两个重要结论。一个是说令一个转移 \(x\rightarrow y\),令其中最小值是 \(d\),应该满足 \((y-x)d\le m\)。原因是一次跳过的代价是 \((y-x)^2d\),而如果一步一步跳的话,每步的最大值是 \(n\),所以代价不超过 \((y-x)n\)。所以呢 \((y-x)^2d\le (y-x)n\),也就是 \((y-x)d\le n\)。另一个结论是说对于一个跳过去的区间而言,最小值一定是在左右端点上。结论显然,第一个乘数在两种策略下是相同的,而第二个乘数显然又有平方之和小于和之平方,所以有这个结论。可以推广,就是
由于第一个限制是一个乘积的形式。考虑根号分治:当 \(d\) 很大的时候,显然合法的决策区间不超过 \(\sqrt N\),枚举就可以了。当 \(d\) 比较小时,会发现根据结论二,上次转移过来的点一定是某个值最后出现的地方。当最小值是之前那个位置时,由于这个东西不会很多,所以随便维护一下就可以了;另一个是最小值是当前值,此时根据结论二只需要维护一个单调栈。于是总的复杂度是 \(O(N\sqrt N)\)。
CF1707D
记 \(G(x)\) 表示不要求真子集的方案数,记 \(F(x)\) 是真实的答案。根据定义枚举有哪些步和上一步不相同,可以得到 \(G(x)=\sum\limits_{i=1}^x\binom{x}{i}F(i)\),根据二项式反演可以得到 \(F(x)=\sum\limits_{i=1}^x(-1)^{x-i}\binom{x}{i}G(i)\)。于是问题就转化成了如何求 \(G\)。
发现一个点 \(x\) 可以被删除当且仅当已经把 \(x\) 删的只剩下不超过一个子树有值。于是可以用 \(f_{x,t}\) 表示子树 \(x\) 恰好在时间 \(t\) 被完全删完的方案数,对两种情况分别讨论。如果删除 \(x\) 时没有一个子树有值了,那么 \(f_{x,t}=\prod f_{y,i},i\le t\)。还有一种情况是只剩下一个子树有值了。枚举点 \(x\) 熄灭的时间 \(r\),也就是说子树 \(z\) 必须在 \(t\) 灭掉,并且其它孩子都应该在 \(r\) 之前灭掉。于是有 \(f_{x,t}=\sum\limits_{r<t}\sum\limits_{z}f_{z,t}\prod\limits_{y\ne z}s_{y,r}\),其中 \(s\) 是 \(f\) 的前缀和。然后发现后面那个东西可以通过预处理前后缀积的方式快速计算。发现可以提前得到 \(f_{z,t}\),所以问题就变成了求 \(\sum\limits_{r<t}\prod\limits_{y\ne z}s_{y,r}\)。随便维护一下就可以了,复杂度 \(O(N^2)\)。
CF1111E
一道挺好的题。首先思考如果树是确定的如何解决问题,发现只需要排个序,然后用 \(f_{x,y}\) 表示前 \(x\) 个点占据了 \(y\) 个集合的方案。对于点 \(x\),如果自己单独开一个集合,那么方案是 \(f_{x-1,y-1}\)。如果放入之前的集合,由于它的祖先们一定不会在同一个集合而是分散开来,所以有 \(anc\) 个集合不能放,所以是 \(f_{x-1,y}\times(y-anc)\)。为了保证祖先先于自己访问,把所有点按广搜序排列就可以了,毕竟祖先的深度一定会比自己小,最后树剖维护一下即可。
CF765F
乐,太乐了,乐麻了。
首先离线所有询问,然后考虑对于每个右端点求答案。对前大后小和前小后大分类讨论,前者可以通过后者反转值域来做。考虑对于当时的 \(a_x\) 有哪些点的答案可能发生改变,假设第一个比 \(a_x\) 小的位置是 \(y\),那么显然 \(a_y\) 可能是有所贡献的。然后再往前走,显然所有比 \(a_y\) 小的数是没有用的,所以要找一个在 \(a_x,a_y\) 之间的数,这种数可能很多,但是发现由于 \(a_y\) 的存在,如果 \(a_z<\frac{a_x+a_y}{2}\) 的话,那么它应该会在 \(a_y\) 处更新(虽然不一定是在这一轮中),所以合法的值域就被缩小了一半。所以右端点每次向右挪动一次就会有 \(\log\) 个位置被更新,每次更新用树状数组维护后缀最大值,复杂度 \(O(N\log ^2V)\)。
CF1149D
考虑求最小生成树的过程。首先会尝试加入边权为 \(a\) 的边(也就是轻边,对应地边权为 \(b\) 的被认为是重边),如果这些边已经可以把整张图联通,那么说明就不需要重边了,在这种情况下显然答案就算起点到每个点的最短路。推广到一般情况,加入轻边之后图会形成一些连通块,连通块中的点不能被重边连接,否则形成的就不是最小生成树了,也就是只有跨越连通块的重边是有效的。但是也有一些方案不合法,比如一个块出去了再回来,想到状压记录。但是连通块的数量很多,不能暴力记录,但是有一个非常巧妙的事情是说小于 \(4\) 的连通块一定不会出现上述情况,因为任意两个点之间最多隔着两条轻边,而你要出去再进来至少需要经过两条重边一定不优,所以在最短路的过程中就不会出现这种情况,所以联通块的数量降到了 \(17\) 个,于是就可以状压跑最短路了。还有一点细节但很好处理,所以忽略。
CF1098C
随着限制放开,下限应该逐渐降低。最低点显然是完全 \(k\) 叉树,可以快速求得。然后思考已知限制的前提下如何快速求解。先构造一条链,每次考虑把最深的那个点向下挪动,显然可以二分,用 set 维护当前没满的点的集合以及其深度即可。复杂度线性对数。
CF1276D
比较强的一道题。首先发现如果删除每个点的边确定了,那么整个序列就确定了,于是问题转化成了如何去求每个点被哪条边删除。明确了这个剩下的东西就比较好处理了,用 \(f_{x,0/1/2/3}\) 表示点 \(x\) 被父亲,被早于父亲边的边,被晚于父亲边的边,没有被覆盖的方案数。需要分别讨论一些下。
如果它不是被父亲覆盖的,也就是 \(f_{x,1/2}\)。考虑钦定一个孩子,比如 \(y\) 作为覆盖当前点的边,考虑如何计算这种情况下的方案数。大概分析一下,如果存在一个孩子 \(y\) 是在父亲之后覆盖,并且 \(x\) 并没有选择它覆盖自己,那么说明 \(x\) 选择的这个孩子一定早于这个 \(y\)。于是可以以枚举的 \(y\) 把儿子们分成两个部分,前面的部分如分析所示不可能有 \(2\) 的状态,同理也不会是 \(3\),总之就是处理完这条边之后两个点不能同时空着。对于后面的点,由于 \(x\) 已经被覆盖了,那么 \(0\) 就算不合法的了,其它状态都是可以的。维护前后缀积分类贡献即可。
剩下的两类比较简单,首先是 \(f_{x,0}\),也就是说那些早的孩子的状态只能是 \(0,1\),晚的孩子可以是 \(1,2,3\)。最后就是 \(f_{x,3}\),由于所有孩子都不能和它产生矛盾,所以答案就只能是 \(f_{y,0/1}\)。复杂度显然线性。
CF920G
二分,然后思考如何检查。问题转化成了求 \(\sum\limits_{i=1}^n\varepsilon(\gcd(i,x))\),考虑莫反。
然后预处理一下就可以了。
CF1534H
一道交互题。傻逼玩意场上我的思路明明是对的,结果由于构造上出了问题成功三个小时爆切零分。发现唯一的区别是可以通过递归的方式给每个子树粗略地剩下来一次询问,就这个区别,而且我明明已经想到了。傻逼玩意。我应该当场退役。
显然用 \(f_x\) 表示已知端点在子树 \(x\) 最坏情况下所需要的步数,显然有贪心的想法,把 \(x\) 的孩子按 \(f\) 降序排序,于是答案显然是 \(\max(d_x,f_y+y)\),有了这个之后就可以思考如何去求根为 \(rt\) 时的答案了。显然还是排序,答案应该是 \(\max(d_{rt},d_{rt-1}+f_0,f_0+f_y+y-1)\),三个部分分别对应三种决策,即两个点重合,一个点是根以及两个点在两棵不同子树中的答案,于是就可以顺着这个思路去构造答案了。最后还剩下一个问题,即如何快速找到每个点为根时的答案,考虑使用换根 DP,发现要用换根 DP 唯一的问题是如何求点 \(x\) 作为 \(y\) 儿子时它的 DP 值,发现答案可以由儿子前缀和儿子后缀的答案合并起来,发现可以用 multiset 方便维护。
复杂度线性对数。
CF1268D
一道神秘的结论题。有结论是说任意一个大于 \(6\) 的竞赛图都可以通过翻转不多于一个点的方式使之变得强连通,而暴力缩点是不优雅的,此时需要用到兰道定理。兰道定理是指假如用 \(d_x\) 表示 \(x\) 的出度,先把 \(d\) 升序排序,那么这个竞赛图合法当且仅当 \(\forall k,\sum\limits_{i=1}^kd_i\ge \binom{k}{2}\)。有一个重要的推广是说,这个竞赛图强连通当且仅当 \(\forall k\in[1,n-1],\sum\limits_{i=1}^kd_i\ne \binom{k}{2}\)。于是这道题就可以简单地翻转之后排序检查即可,复杂度 \(O(N^2\log N)\)。至于小于 \(7\) 的图,由于问题规模非常小可以直接暴力尝试翻转然后检查即可。
CF1063F
把字符串翻转并把限制取反显然不影响答案。另外一个就是一定存在一种最优解使得第 \(i\) 个串的长度恰好是 \(i\),因为其它情形转到这上面肯定不劣。
用 \(f_x\) 代表最后一个串以 \(x\) 结尾的最优答案,显然有 \(f_x\le f_{x-1}+1\)。用指针维护 dp 值,于是问题转化成了当前值是否合法。也就是询问是否存在一个结尾不超过 \(x-t\) 的并且答案不小于 \(t-1\) 的点,并且希望这个串是点 \(a_{x-t+1\dots x}\) 的子串。换句话说当前串减去前后两个字符得到的两个串一定有一个是某个前缀的后缀,分别查询即可,于是问题转化成了当前的两个指针 \(p,q\) 中是否有一个的子树中存在 \(t-1\),单点修改子树最大值即可。由于查找范围,即 \(i-t\) 是单增的,所以只需要加入贡献点即可。
最后就是如何找到指针 \(p,q\)。上一个前缀的两个指针相较于这一个而言其实只是增加了一个字符 \(a_i\),所以初始只需要往后走一个即可。然后在 \(t\) 缩水的过程中和往常一样,如果当前 \(len\) 已经和父亲契合了就往上跳就可以了。复杂度 \(O(N\log N)\)。
CF1205D
一道很妙的题。首先思考假如题目要求的是 \([1,m-1]\) 都出现,只需要给每个点赋一个深度(当然这个深度应该是要合法的),然后根据自己深度和父亲深度的关系构造边权即可。然而此题要求的是 \(\dfrac{2n^2}{9}\),可以看成是一个二位数,并且其能表示的数应该不小于题目要求。具象化地就是找一个根,然后把子树分成两个部分,一部分的深度是 \([0,x-1]\),另一部分的深度是 \(0,x\dots(y-1)x,yx\),二者凑起来就可以构造出 \([0,xy+x-1]\) 中的数。而中心有一个性质就是不存在过大的儿子,那么就存在方法把子树尽量平均分配,于是这个限制就可以满足了。
CF961F
一个重要的技巧是考虑对于 \(x\) 的答案思考它和 \(x+1\) 的答案的关系。发现对于 \(x\) 的情况,把匹配的串的第一个和最后一个字符删掉就可以得到一个合法的 \(x+1\) 的答案,于是有结论是说 \(f_{x+1}\ge f_{x}-2\),变换一下方向就是 \(f_{x}\le f_{x+1}+2\)。于是可以先继承上一个点的答案,然后向下挪动指针并在这个过程中用哈希检查是否合法,这种方法下找到的第一个相同串就是最大的答案。根据指针挪动的方式可以发现其移动距离是 \(O(N)\) 的,所以复杂度是线性的。
CF799F
一道神秘哈希题。第一眼看那个限制就特别哈希,不知道为什么。但是一般而言我们希望哈希值为 \(0\) 比较好,因为这样可以通过前缀和相互异或得到,但是奇数的限制比较讨厌,于是题解区给了一个比较妙的处理方法。考虑询问区间和值的区间的关系,如果完全相离当然没关系,如果包含值的左端点考虑把左端点和询问的左端点往右挪动一个,这样可以改变奇偶性而不改变其它内容;否则左端点肯定是在值的区间之内的,那么左端点向右挪动显然只会改变奇偶性。总结起来我们只需要把询问和值的左端点都向右挪动,这样就可以把限制转化成要求区间内 \(1\) 的个数为偶数,也就是异或和为 \(0\) 了。区间内没有值的情况非常容易处理。然后有一点细节。
CF1299C
一道很简单但是我傻逼了的题。一个显然的结论是说最后出来的序列是不减的,也就是说从后向前的平均数应该是不减的,这比较像单调栈的性质。于是考虑维护一个单调栈,从左到右扫描,每次尝试加入一个长度为 \(1\) 的并且平均数为当前数的块,并尝试维护单调栈的性质,最后按顺序输出即可。
CF1572C
一个可以想到的结论是一个区间最后停留的颜色应该是最左边的颜色或者最右边的颜色,而二者是等价的,结合数据范围可以用 \(f_{l,r}\) 代表区间 \([l,r]\) 最后全部统一成 \(a_r\) 所需要的最少次数。朴素的方法是 \(f_{l,r}=\min f_{l,x}+f_{x+1,r}+[a_x\ne a_r]\),然后题目中的限制使可以猜想转移点,尝试只枚举相同颜色的位置更新即可,复杂度 \(O(N^2k)\)。
CF1320D
发现一次替换可以看成是一个 \(0\) 点向左或者向右平移了两个位置,这使得这种移动具有几个性质,一个是比较显然地 \(0\) 的数量不会发生改变,一个是两个 \(0\) 的相对位置不会发生改变,另一个是一个 \(0\) 它位置的奇偶性也是不会发生改变的。于是猜想有结论两个串可以相互得到当且仅当 \(0\) 位置相同并且对应位置奇偶性相同,想到使用哈希。由于有可能起始点奇偶性不同,所以需要维护两个哈希数组分类讨论。几乎没什么细节。
CF1320E
一道典型的 zyc 题目,具体表现为一车图论板子套起来,并且没啥代码难度只是写起来很烦。根据题目数据的限制,对所有初始点和目标点建虚树,然后考虑如何解决这个问题。考虑超级弱化版,如果每个颜色延伸速度相同,那么求的就是每个目标点距离哪个起始点最近,可以使用多源最短路也就是 dij 来解决;而实际上题目更为复杂,因为不仅要考虑到边权,还要考虑到颜色之间的染色顺序等。于是考虑拓宽节点的含义,给其加上三个维度:当前轮数,颜色,以及剩下的可行距离,三者优先级从高到低,然后用这个去跑堆优化最短路就可以了。代码比起其它 CF 题目略长,但细节确实不多。
CF1495D
首先有一个比较重要的结论是说如果两个点之间有多条最短路,那么这两个点是没有答案的,因为这两条最短路必须断掉至少一条,那么上面的点就会不符合条件,于是就会寄掉。然后问题就非常简单了,由于最短路上的点连边已经确定了,而剩下来的点一定满足两个点在同一个方向,于是只需要在邻点中选择满足两个点最短路限制的点作为父亲即可,会发现每个点的决策是独立的,把所有合法的点数乘起来就可以得到答案,复杂度 \(O(N^3)\)。
CF1290F
一道非常具有启发意义的题目。首先向量集合以及每个向量的选择次数确定了之后整个凸包就已经确定了,因为凸包肯定会按照角度选边,于是问题转化成了一车向量,并且需要满足 \(\sum x_i=0,\sum y_i=0\),并且要满足其 \(\sum[x_i>0]x_i\le lim,\sum[y_i>0]y_i\le lim\) 的限制。但是问题在于题目中 \(lim\) 的范围非常大,以至于到了 \(10^9\) 的级别,显然不能用贪心之类的方法来做。而考虑到向量数量很少,并且值域也很小,所以可以有神仙的想法,也就是使用数位 DP 来解决这个问题。
设计状态,用 \((wh,ax,ay,dx,dy,lx,ly)\) 表示已经确定了前 \(wh\) 位,前 \(wh-1\) 位对这一位的贡献,也就是进位,是 \(ax,ay,dx,dy\),分别表示 \(x\) 这一维正数的绝对值、负数的绝对值,以及 \(y\) 这一维的值。\(lx,ly\) 分别表示两个维度上正数的绝对值之和在前 \(wh\) 位是否严格大于 \(lim\)。转移方面暴力枚举当前位填的什么,唯一需要保证的是两个维度正数和负数绝对值当前这一位的值是一样的,然后正常转移即可。会发现用记忆化搜索非常好写,并且木有细节。
CF720F
无论如何这是一道很强的题目。
感性理解可以发现这玩意的斜率是单减的,因为如果你当前斜率比之前更大那么你完全可以把当前决策用在之前的某个时刻之上,于是就可以使用 wqs 二分来解决这个问题,需要注意的是二分的上下界应该分别取到正无穷和负无穷,因为显然到了后期可能再选区间只能选到价值为负的区间了。
思考 check 函数里的内容。用 \(f_x\) 表示已经覆盖了 \([1,x]\) 的位置所能选到的最大价值,用 \(v\) 表示当前二分出来的斜率,考虑转移。首先有贪心的想法,对于 \(s_x-s_{y-1}\ge v\) 的位置 \(v\),我们显然可以贪心地选择这些区间,记其中最小的 \(y\) 为 \(L\),那么此时我们已经覆盖了 \([L,x]\) 中的点,思考如何覆盖 \([1,L-1]\) 中的点。此时分成两种决策,如果我们选择了一个点 \(z\) 满足 \(z\ge L-1\),那么我们可以选择 \(z\) 和前面的贪心合并得到 \([1,L]\),显然可以把前缀和排序之后二分和树状数组维护即可,此时贡献就是 \(f_z+V\)。还有一种决策是说我们可以选择一个 \(z< L-1\),但是中间会形成一个空当,这就需要我们再选择一个区间去弥补这个空间,于是我们需要选择一个 \(L'\le z+1\),此时得到的贡献是 \(f_z+V+(s_x-s_{L'-1})=V+s_x+(f_z-s_{L'-1})\)。发现后面相当于贪心地找位置小于等于它并且最小的前缀和,直接维护即可,然后把后面那一堆当成一个整体来维护,于是问题变成了单点修改前缀查询,也可以在一只 \(\log\) 的时间内解决。
于是总的复杂度是 \(O(N\log^2 N)\)。
后记,思路有些小问题,有些细节与事实有一些出入。然后我的线段树被卡常了,但我生成正确性和复杂度是没有任何问题的,单纯是 CF 的机子慢。大哭。
CF1322E
一道很有用的题目。首先考虑如果序列元素都是 \(01\) 怎么做,发现如果有连续两个相同的数在一起的话那么它们就一直不会变,也就是说会变的只是那些连续的 \(01\) 交错的段。而它们恢复的情况显然是从外向内一层一层地恢复,所花费的时间显然是 \(\frac{len}{2}\),颜色情况是左一半和左边一样,右一半和右边一样,不存在中间点因为如果长度为奇数那么做有点的颜色一定一样,一个串恢复平静显然当且仅当所有条件下染色方案均是稳定的,所以只需要枚举每种染色方案,找出所有方案下 \(01\) 串的最大值即可。至于输出方案,只需要找到每个点第一次平静于 \(1\) 的点即可。
实现上用 set 来维护,每个节点维护一段 \(01\) 交错的序列,然后更新的时候大力分类讨论即可。复杂度 \(O(N\log N)\),估计会有一点卡常数。当然还有更好的实现方式,即 set 中只存储每个段的右端点,这样也能正常更新,并且还能减少更新次数,比较妙。
CF713C
直接说 \(O(N\log N)\) 的做法。感觉是一种很强的思路。
首先列出暴力的方程,用 \(f_{x,y}\) 表示把 \(a_x\) 变成 \(y\) 的最小代价,那么显然有转移方程 \(f_{x,y}=\min\limits_{t\le y}(f_{x-1,t}+|a_x-y|)\)。然后观察这个柿子的性质,可以拆成两个部分,首先是 \(|a_x-y|\) 的部分,发现这显然是一个单谷的函数;而 \(\min\limits_{t\le y}f_{x-1,t}\) 相当于是把上一轮的 DP 值加了个水平切线,实际上仍然是单谷的,于是两个函数叠加起来得到的这一轮的函数应该也是单谷的,这是本题最重要的一个结论。
然后就是这道题我认为最强的部分,也就是实现方面。我们可以维护一个大根堆,大根堆中的元素是每段斜线的右端点,其斜率是要把它 pop 出来所需要花的次数。这样相当于是有一个好处,如果我们加入一个元素就相当于是给全体元素的斜率 \(+1\),相反删除一个元素就相当于 \(-1\)。最后就是决策上的问题了,如果当前的 \(a_x\) 已经在平缓处后面了,那么可以发现你完全不用去管它;如果它还在下坡的某个地方,那么说明当前的最优决策点实际上是在最后一段斜线的末尾处,画图就可以得到这个结论,然后这个绝对值函数叠加上来的影响其实就是把后面的那些线段斜率加一,并把前面那些元素斜率减一,体现在堆的操作中就是丢出堆顶并把当前元素丢入堆中,同时统计答案即可,复杂度一只 \(\log\)。还是非常巧妙的。
CF1140F
一道比较套路的题。感性理解会发现如果把横坐标和纵坐标连边,会形成一些连通块内,然后发现其中两部分别都是可以连边的,其实感觉上比较显然。于是问题就变成了询问当前经过一车加点删点之后还剩下哪些连通块,并且询问这些连通块有多少横坐标以及纵坐标,线段树分治即可,很好写。
CF1142C
题意大概是说需要找到一些抛物线,使得至少有两个点在抛物线上并且其它点都在抛物线的下面,求合法抛物线的数量。考虑抛物线 \(y=x^2+ax+b\) 和一个点 \((x,y)\) 什么时候合法,也就是说希望 \(y\ge x^2+ax+b\),移项得到 \(y-x^2\ge ax+b\),感觉上就是该直线在一个点上面的形式,于是把每个点转化成 \((x,y-x^2)\) 的形式,然后对点集求上凸包并输出凸包大小即可,注意不能出现斜率正负无穷的直线。
CF1656F
首先思考 \(t\) 给定时最小生成树应该如何构造。考虑转化一下它的那个柿子,\(a_ia_j+t(a_i+a_j)=(a_i+t)(a_j+t)-t^2\)。发现对于一个点数已知的生成树,其边权减去的 \(t^2\) 数量是固定的,所以我们只需要让前面的 \((a_i+t)(a_j+t)\) 最小即可,这里可以贪心。令 \(b_i=a_i+t\),显然当 \(b_x\) 为正数时它会贪心地连到最小的边;相似地,当 \(b_x\) 为负数时,它会贪心地连到最大的边,会发现这样出来的恰好是一棵树,所以这种策略显然是最优的。
然后考虑怎么判断无解,显然当 \(t\) 为正负无穷的时候如果最优边权是正无穷的话答案就是无解的。以 \(t\) 为正无穷举例,此时显然所有的 \(b\) 都是正的,那么最优构造应该是都往最小的点连边,边权此时应该是 \((a_1+t)(a_2+\dots a_n+nt-t)-(n-1)t^2=a_1(a_2+\dots a_n)+(a_2+\dots a_n-(n-1)a_1)t\)。前者是常量,所以只要后面 \(t\) 的系数是正数就能凑出正无穷,所以这一支的条件是 \(s_n-s_1>(n-1)a_1\)。相似地,\(t\) 为负无穷的那一支的条件是 \(s_{n-1}+a_n(n-1)<0\),判断即可。
最后就是求最优解,枚举 \(t\) 的值并简单计算就可以啦。
CF1100F
算是一个 trick 吧。考虑离线然后从左往右扫描,同时维护一个特殊的线性基,每个元素除了维护其值以外还维护了一个时间标记。询问的时候只能访问那些在当前左端点之后的节点更新答案,插入的时候如果发现当前节点的时间比自己古老,就强势用自己取代它,更新时间并交换自己和节点原有的值和时间,然后依次向下更新即可。写法上有点要注意的,就是说如果当前节点是 \(0\) 的话要直接返回。
CF1394C
容易发现第二个操作,如果序列中两种字符都有的话那么一定是可以进行操作的。于是(当然它的样例也是给得非常良心哒)会发现一个序列可以用 B,N 的数量来刻画,然后这些操作分别对应了两个维度上的加加减减。显然转到平面上,然后 dis 函数的含义就变成了平面上两个点之间的最短路,问题变成了找到一个点使之到所有点的最大值最小。
二分答案,对于当前二分出来的 \(v\),考虑有哪些点可以在 \(v\) 步之内到达 \(p\),显然合法的点集会形成一个六边形(也可以看成是一个正方形砍掉两个角),看成是六个半平面随便求交即可。然后输出方案是有点细节但不多,挂了纯纯是因为我脑瘫。
CF1286F
ban 掉序列中值为 \(0\) 的数。然后剩下的每个数至少都要被操作一次,而假如每次第二种操作都给对应的两个位置连上边,可以想到图应该是不会出现环的,换句话说任意点集如果要用第二次操作的话操作数一定应该小于点集大小。所以每个连通块都应该是一棵树。
假如操作二没有那个 \(1\) 的差,那么可以从叶子到根计算每条边产生的变化量,而唯一的限制就是根出去的所有边的变化量加起来应该刚好为 \(0\),画图发现这个变化量之和其实就是深度为奇数和偶数的两个点集的权值之差,所以问题变成了找到两个点集使得它们和相同。但是实际上操作二是有 \(1\) 这个东西的,所以限制可以放宽成两个点集差的绝对值小于点集大小,并且权值和与点集减一应该满足奇偶性相同。
还有一车细节以后有时间补。
CF1517F
转化成有多少种方案满足存在一个白点,其 \(len\) 以内的点都是白点。仍然不很好求,考虑什么是不合法的方案,发现不合法的方案等价于对于任意一个点,其 \(len\) 以内是存在黑点的,可以看成是黑点把树上所有的点都覆盖了,考虑如何求方案。用 \(f_{x,t}\) 代表假如这棵子树上面挂了一条无限长的链,那么这棵树中最浅的未被覆盖的点与点 \(x\) 的相对深度差为 \(t\) 的方案数,最后不合法的方案显然是 \(\sum\limits_{t>1}f_{root,t}\)。考虑转移,可以想到当子树比较小的时候合法状态不会太多,事实上合法的状态数是子树大小级别的,所以可以考虑枚举出两部的合法状态并尝试更新。总的复杂度就是 \(O(N^3)\)。
CF1368H1
感觉上非常具有启发意义。首先建出图,答案就等于最大流,也就是最小割,但是由于数据范围太大了必须观察题目性质。考虑假设内部的所有点都是红色的,那么此时的割就是蓝点的个数,考虑如何把内部的一些点染成蓝色使得割的大小减少,这里有一个结论是说最后蓝色的点一定是一整列一整列出现的,考虑证明一下。首先是如果中心有一个孤零零的蓝色连通块,那么把它变成红色一定会更优;如果红蓝边界出现了一个凹字形的蓝色块,那么把凹陷处补平一定不劣。还有一些边角情况考虑一下就可以发现上面那个结论是正确的。于是就只需要进行 DP,用 \(f_{x,0/1}\) 表示前 \(x\) 已经染色并且最后一列是红色或者蓝色的最小割的大小,转移上非常简单。至于 H2 就是在 H1 的基础上套上了一个动态 DP 的壳子。
CF1264C
记 \(E\) 为当前这个标记点走到下一个标记点需要的期望步数,显然可以得到:
其中 \(pre_x\) 表示前缀 \(x\) 全部成功的概率,\(fail_x\) 表示 \(x\) 点失败的概率。考虑如何快速维护上面那个式子。\(pre_n\) 显然可以维护前缀来计算。而后面那一堆其实可以看成是这样的:
用线段树维护区间加即可。然后考虑修改产生的影响,实际上产生的影响只有 \(pre\) 数组,所以实际上要做的就是一个区间乘区间查。随便做。
CF1264D2
首先思考给定一个串,可能的最优策略是什么样的。由于题目中只是要求了深度最大,所以可以枚举最中心的那个点 \(p\),于是答案就是 \(\max\limits_{1\le p\le n}\min(l_p,r_{p+1})\),其中 \(l_p\) 表示 \([1,p]\) 中左括号的个数,\(r_{p}\) 表示 \([p,n]\) 中右括号的个数。
此时有一个非常重要的保证我们后续操作不会算重的结论,即对于一个序列我们在 \(l_p=r_{p+1}\) 的地方统计答案是正确的。首先这个点肯定是合法的,因为宏观来看 \(l\) 显然是单调不降的,而 \(r\) 是单调不升的;同时这个点又是唯一的,因为随着指针 \(p\) 的移动,两个值一定会有一个产生变化。综上,在这里统计是正确的。
然后就只需要枚举这个 \(p\) 和答案,尝试着让两边的左右括号数量相等。用 \(l\) 代表左边的左括号数量,\(r\) 代表右边的右括号数量,\(u\) 表示左边的问号数量,\(v\) 表示右边的问号数量。答案就是:
暴力去做显然是 \(O(N^2)\) 的,可以过掉 easy version。考虑化简柿子。
然后就可以线性计算啦。
CF1097F
由于值域比较小,考虑用 bitset 来维护每个值出现的次数。对于每个 bitset \(A\),用 \(f_A\) 来刻画其倍数位上的关系,即 \(f_x=\sum\limits_{x|y}A_y\)。发现可以快速用 \(f\) 还原出 \(A\),具体方法反演即可,即:
对于每个 \(x\) 预处理 \(\mu(\frac{x}{y})\) 即可快速回答操作四。而其它操作都是比较简单的,除了操作三,而上述的表示法可以加快三的计算过程,具体如下:
然后就没了。复杂度 \(O(Q\frac{V}{\omega})\)。
CF1097D
为了加快计算速度,考虑对于每个质因数分别考虑。假设当前指数是 \(a\),每次相当于是在 \([0,a]\) 中等概率取一个数,随便递推一下即可。会快很多。
CF1726D
本来是一道非常非常简单的题,但是由于我傻逼了吃了一万发罚时。首先就是 unique 之前一定要 sort,然后就是一棵树加入一条非树边的时候删除的应该是更深的那个点的父亲边,这样是非常好写且正确的。至于题目本身没什么好说的,考虑搞一棵生成树令其为白色,其它令为黑色。发现白色每删一条边就会多一个连通块,黑色加一条边会少一个连通块,这显然是最优的方案;但是黑色有可能会形成一个三元环,随便破坏掉一条边即可。
CF1540B
本身并不难,只是有一点细节。数据范围比较小,考虑枚举根之后枚举点对看他们形成逆序对的概率。如果有祖先关系可以直接判断,其它的情况需要借助 LCA。发现在 LCA 被遍历之前两个点是没有什么关系的,而在 LCA 之后呢选择的点有三种可能,一种是 \(A\) 的祖先,一种是 \(B\) 的,一种是其它。发现第三种可以忽略,前两种的概率其实是相同的,于是问题变成了有一个网格图每次向上或者向右走一个,先走到上或者右边界的概率。
需要注意的是概率不能直接用路径数除以总路径数,因为每条路径的概率不同。比如 \(2\times 3\) 的网格走到右下角的那个点的概率其实是 \(\frac{1}{4}\),但是总的路径只有 \(3\) 条,于是就出现了问题。卡了很久。正确的做法就是用递推求概率,反正这道题这个方法是可以承受的。然后就没了,复杂度 \(O(n^3)\)。
CF1801D
考虑一种比较好考虑的情况,即在初始点表演可以获得非常多的金钱,以至于在这里表演可以比在任何其它点表演赚钱效率都高,那么我们的策略一定是先确定一条从起点到终点的最短路,然后计算差的钱数,在起点表演这么多次之后一口气到达终点。推广开来,贪心地我们肯定会选择在效率最高的一个点进行表演,并且刚好表演到可以到终点的地步。但事实上我们很有可能会选择多个点进行表演,这是因为我们初始的钱数不支持我们到达效率最高的点。但是这里有一个结论是说,假设存在两个表演点 \(a,b\),并且我们会先到达 \(a\),那么我们在 \(a\) 表演的次数一定是使我们能够到达 \(b\) 的前提下的最少次数,理由很简单,我们在 \(b\) 也表演一定意味着在后者表演效率更高,既然如此我们肯定会尽量在第二个点进行表演。还有一个显而易见的结论是最优路径不会存在环,毕竟环上一定是会消耗金钱的。于是跑一个单源最短路即可,只是更新出边的时候是枚举所有下一个点,边权就是上面说的最少表演次数,正常更新即可。有些细节但不多。
CF1726E
首先需要分析出什么样的排列是合法的。题目中 \(q_{p_x}=x\) 的限制比较神奇,考虑从 \(x\) 往 \(p_x\) 连边会发生什么。据说经过少量的手玩可以得出结论,连成的环只可能是三种情况,自环,二元环和形如 \((a,b,a+1,b+1)\) 的环。有了这个结论计数就简单了,记 \(f_x\) 为只有一二元环的方案,显然枚举一号点的情况,有 \(f_x=f_{x-1}+(x-1)f_{x-2}\)。接下来思考四元环的方案。
首先选出 \(2x\) 对相邻的值的方案是 \(\binom{m-2x}{2x}\),具体地就是说考虑在 \(m-2x\) 中选择 \(2x\) 个数,在他们后面填上相邻的数就是合法答案。然后这些值配对的方案,枚举每个点的匹配对象应该是:
考虑到每对数之间有顺序,所以总的答案应该是:
计算即可,复杂度 \(O(\sum n)\)。
CF908G
考虑对于 \(1\dots 9\) 中的每个数字分别考虑贡献。用 \(f_x\) 表示已经填了前 \(x\) 位所有方案下的贡献,用 \(g_x\) 表示如果在所有方案中加上一个数 \(x\) 会产生的变化量。枚举这一位填的是什么数,然后根据它和当前数的大小关系考虑贡献即可。复杂度 \(O(d^2n)\),其中 \(d\) 是字符集大小,即 \(10\)。
CF1438F
一道非常披风的题目。考虑 LCA 的另一种含义,即给定根 \(r\) 和两个点 \(x,y\),那么 LCA 就是距离这三个点最近的点,很好理解。考虑基于此进行判断。考虑根成为 LCA 的概率,直觉上并不会特别大,因为必须要三个点中恰好有一个根才行。剩下的点中只考虑那些度为 \(3\) 的点,还是一样的,有一个点恰好等于它的概率比较小不考虑,那么剩下的情况就是这些点分属三个不同的子树。显然三个子树的大小分布得越平均方案就越多,就越可能成为答案,所以发现根的两个孩子成为答案的概率远远大于其它节点。所以只需要用 \(400\) 次随机询问,然后对答案排序,认为前两大的节点就是两个儿子;然后枚举节点,随便判断一下它是不是根即可。可以通过。
CF573D
感觉上非常具有启发意义。如果没有不能骑对应马的限制,那么显然有贪心的想法,即把人和马分别排序,然后贪心地将排名相同的人和马分在一组,显然这样是最优的。但由于限制的存在,这样的方案很可能是不合法的。此时有一个重要的结论是说最后的最优方案一定满足每个人的马和他的排名差不会超过 \(2\)。可以大概感性理解一下,就是说如果存在一个跨度为 \(3\) 的匹配,那么完全可以让一个能力值更大的人来骑这匹能力值更大的马,除去正在被调整的这个人还有三个人和三匹马,被调整的这个人一定可以在更劣的三匹马中找到合适的,而剩下的三个人也一定可以找到一组合法的匹配,这样显然是更优的,于是就得到了上面那个结论。然后就可以进行 DP 了,用 \(f_x\) 表示前 \(x\) 对人马已经匹配完成的最大价值,考虑最后几个人内部消化的,转移就是 \(f_x=\max(f_{x-1}+a,f_{x-2}+b,f_{x-3}+c)\),其中 \(a,b,c\) 可以暴力计算。由于题目中要求带修,所以转成矩阵形式动态 DP 即可。