题4

P2704 [NOI2001] 炮兵阵地

古早的题目。注意到\(m\)很小,并且只关心上面两层的状态,所以可以直接压入状态。\(f_{i,S,S'}\)表示考虑到第\(i\)行,前两行中的第一行为\(S\),第二行是\(S'\)。然后枚举当前行转移就行了。会爆。剪枝,把不合法状态判掉。然后枚举第\(i\)行的时候使用枚举子集的方法,然后就行了。数组滚动一下。

P6192 【模板】最小斯坦纳树

\(f_{i,S}\)表示以\(i\)为根联通了关键点的集合为\(S\)的最小代价。枚举根节点\(i\),然后分成两种情况转移。如果树上\(i\)的度数为\(1\),那么就找与\(i\)相连的内阁点\(j\),用\(f_{j,S}+w_{i,j}\)来更新\(f_{i,S}\)。度数大于\(1\),用\(f_{i,T}+f_{i,S/T}(T\subseteq S)\)。对于第二种情况就按照\(3^k\)枚举,第一种情况跑最短路。具体的。先枚举\(S\),得到所有\(i\)的度数大于\(1\)的值。然后通过最短路更新度数等于\(1\)的值。为什么对呢?首先对于第一种转移时\(f_{i,T},f_{i,S/T}\)一定是正确的,但此时发现一些实际度数为\(1\)的方案就被贡献了多次,那么,最短路就是用来处理这种情况的。那么就好了。

P4127 [AHOI2009] 同类分布

就是发现数位和总共只有\(162\)种,所以可以暴力枚举数位和,然后跑数位\(dp\),然后数位\(dp\)适合用记忆化搜索写,这样应该会快一点。

s21461

首先一个比较重要的性质就是我们可以让豌豆都排满,然后再把剩下的空格插进去。那问题就是找把\(n\)个豌豆紧密排布最后长度为\(x\)的方案数。那其实就是一个连续段。对于连续段问题我们可以考虑使用连续段\(dp\)。就是先放一下连续段,然后对于一个数,把他合并到其他连续段或者单开一个连续段,又因为这个题放豌豆时有\(r\)的限制,所以我们可以想到可以将\(r\)排序,这样放\(i\)的时候就能保证贡献只和\(i\)有关了。具体的我们设\(f_{i,j,k}\)表示说放了前\(i\)个,一共有\(j\)个连续段,使用了\(k\)的长度的方案数。容易想到的转移是把\(i\)放到一个连续段的左右两边或新开一个连续段。但是这样发现少了情况,就是\(i\)操作完以后再某个连续段的中间的情况。这种情况我们让\(i\)放到一个连续段的左边和一个连续段的右边来解决。式子是好推的。

总结:连续段\(dp\),除了放到连续段左右两边和新开连续段的操作,还要包括使用当前值合并两个连续段的操作。

分糖果

这个可以二分是不难发现的,那如何判断是否可行呢?假设\(k\)颗糖果,有\(x\)个箱子,那么一共所需要的糖果数就是\(kx\),设每个人向前\(x\)个箱子里面放了\(c_i\)个糖果,那么如果\(\sum{c_i}=kx\)那么就可以,因为顺着填就行。然后考虑什么情况下能凑出来\(kx\),然后就是\(\sum{c_i}\)是有范围的,最大时就是\(\sum_{\min(a_{i},x)}\)。最小的是\(\sum{a_i-\min(m-x,a_i)}=\sum{\max(a_i-m+x,0)}\)。那么到这里\(O(n\log^2n)\)的做法就已经有了。就是开权值线段树然后二分套二分。然后直接线段树二分就是\(O(n\log n)\)了。

qoj7236

这个题还挺有意思的。首先考虑为什么定理成立。假设每个数出现的次数为\(c_i\),那么交集总数就是\(\sum_{1}^{2n}\binom{c_i}{2}\)。假设不存在,那么总数就\(\le(\frac{n}{2}-1)\binom{n+1}{2}\)。并且考虑,交集总数的下界是什么,额,感性理解就是\(c_i\)取得比较平均的时候,就是\(n\binom{\frac{n}{2}}{2}+n\binom{\frac{n}{2}+1}{2}\)。就有不等式了。但是这个等式恒不成立,所以也就说明定理成立。接着我们继续考虑,就是暴力肯定过不了。那根据不等式的思路,我们考虑先找到一个集合,然后通过这个集合找另一个集合。假设一个集合与另外集合的交集总数为\(C\),若\(C>(\frac{n}{2}-1)n\),根据抽屉原理,一定会存在另外一个集合和他交集总数大于等于\(\frac{n}{2}\),剩下就好说了,与其他的集合交集总数就考虑每一个数的贡献就行了剩下的跑暴力就行了。

qoj7258

\(trick\)太nb了!!!

就是把二维随机游走转化一下。因为二维随机游走\(x,y\)不是很独立,总有一个变而另一个不变。这时神级转化来了,换系,令\(u=x+y,v=x-y\),此时\(u,v\)互不干扰,就是说,\(u+1\)\(v\)\(-1\)\(+1\),同理\(u-1\)。这就很好,在解决一些问题有奇效。
接着我们继续考虑,找的是期望多少个格子\(\times 4^N\),其实就是找所有路径中不同各自的数量,那么考虑每一个格子的贡献,就是找经过这个格子的路径数是多少,进一步的就是找这个格子被第一次遍历到的方案数,然后再乘上一个系数。我们令\(g_i\)表示第\(i\)步时碰到了一个没走到的各自的方案数,然后后面的任意走,那\(ANS=\sum_{i=0}^{N}g_i\times 4^{N-i}\)。考虑求\(g_i\)。发现很难求,考虑拆到每个点上去求,设\(G_i(P)\)表示第\(i\)步第一次走到\(P\)的方案数是多少,发现还是不是很好求,但是令\(F_{i}(P)\)表示第\(i\)步走到\(P\)的方案数很好求,同时我们设\(H_i\)表示\(i\)步走回原点的方案数,因为有了上面的转化,所以不难得到\(H_{2i}=\binom{2i}{i}^2\),那\(F_{i}(P)=\sum_{j=0}^{i}G_{j}(P)\times H_{i-j}\)又因为\(\sum_{P}F_{i}(P)=4^i\),所以\(F_{i}=\sum_{j=0}^{i}G_j\times H_{i-j}=4^i\)\(F_{i},G_i\)表示所有\(F_{i}(P),G_{i}(P)\)的和。到了这步就要结束了,因为\(H_0=1\),所以\(G_i=\sum_{j=0}^{i-1}G_jH_{i-j}\)。那就做完啦!!(虽然可以生成函数做到\(O(N\log N)\)但是我不会)

好题!! 好题!!!

补充:因为模数不是质数,所以应当采用递推的方法;若模数太小,则还可能用到lucas定理。

qoj17158

朴素的暴力就是看到一个回文串,就把他需要保证相同的点之间连上边最后找连通块数量就行了。这样肯定炸。然后就考虑能不能优化一下。当只有两个回文前缀是\(x>y\),当\(2y\le x\)时,发现只需要保证\(y\)是个回文串,然后将再\(x\)中前缀\(y\)和后缀\(y\)对称一下,最后保证前后缀夹得中间的位置保证是回文串就行,因为前缀\(y\)的方案数确定了,那后缀也就确定了,所以答案就是\(y\)的方案数乘上中间是回文串的方案数就行了。接着是\(2y>x\),发现前后缀之间有交集,交集大小为\(2y-x\),并且\(y\)一定是\(x\)的一个\(border\),因为\(x\)是回文串,回文串反过来还是原来的字符串。又因为\(2y-x\)是交集,所以是\(y\)的一个\(border\),结合\(y\)是回文串,能得到\(2y-x\)也是回文串,所以可以把\(x\)限制变成\(2y-x\)的限制。那具体的算法流程就是每次找出最大值和次大值,然后进行上面的操作,一直下去,但是有个问题,当最大值和次大值操作一次后,可能最大值和次大值还是这两个数。所以我们考虑加速一下。操作其实就是将最大值\(-2(x-y)\),也就是最大值和次大值轮流减,所以注意好边界然后直接一次性减完就行。

AT_arc214_f [ARC214F] Unpredictable Moves

网络流的建模太吃操作了,不过这道题似乎是经典题。

就是说,找到四联通路径。如果没有不能连续走两次同样方向的限制的话,那就是直接判定不存在第一行和第一列障碍的八连通就行了,但是有这个限制。我们考虑,如果让\(\to\to\)这样的路径可以走,就是\(\to\uparrow\downarrow\to\)\(\to\downarrow\uparrow\to\),只有当上下都有障碍的时候才不能走,同理先走上下也是一样的,也就是说,出了八连通,类似#.#的也算是联通,这样也不能走,总结就是曼哈顿距离不超过\(2\)的都算联通,那建图就建好了。。。剩下跑网络流找最小割就好了。建图时注意,起点是第一行和最后一列,汇点是第一列最后一行,所以建图的时候要考虑把距离那些边曼哈顿距离不超过\(2\)的点连上,并且\((1,2),(2,1),(N-1,M),(N,M-1)\)慎连。并且不能少建边,加限制条件的时候要考虑是否有特殊情况,要不然会调很长时间。最后这道题卡常!!!!!!

这个转化需要记住,感觉很有用。

CF1517G

这个,他说的条件看起来很难搞,但是和老C的方块挺像的,都是找到一个相似的结构,然后建出来图最后跑网络流最小割。这道题呢,就是一个相似的结构是\((1,0)\to(0,0)\to(0,1)\to(1,1)\)\((0,1)\)表示奇偶。那么就做完了!!只需要把图建出来跑最小割就行了。

总结:遇到有多个不可以并且在网格里面时,考虑不可以的相似结构,可能是格子的奇偶,也可能是格子的形态,或者是与格子周围的形态有关的结构,如果有这些的话,那么可以根据问题要求什么来决定是否采用网络流

代码源

这个前面的还好,就是排名一定相同这个结论也猜到了,更新权值也想到了。就是把\(c_{i,j}\)赋值成\(max(pre_{i,j},suf_{i,j}+k)\)\(pre_{i,j}\text{表示}\max{k=11}^{j}c_{i,k}\)\(suf\)同理。最后的一步我的想法是每一行和每一列连边流量为权值,但是有两个问题。1.就是没有保证一个点只与另一个点匹配,2.边数太多的直接跑网络流会炸。解决方案呢?首先性质是\(c_i\) 是单调不增的并且最大值与最小值差值不超过\(k\)这个通过更新权值的方案就能得出。那么我们考虑一开始就把所有最大值都加到答案里,把其他数都减去最大值。此时边权一定都小于等于\(k\)。那么我们考虑怎么减少边,因为好多相同的边权连到了不同的点上,所以我们可以考虑把右部点连成一个链,就是让\(i\to i-1\)因为\(c_i\)是单调不增的。然后让\(i\)向边权相同的最大的\(j\)连一条费用为\(v\)流量为\(1\)的边\(v\)就是边权,这样保证了一个边只会匹配一次。,\(s\)向行连费用为\(0\)流量为\(1\)的边,这样保证了每一行只会匹配一次,每一列向\(t\)连一条费用为\(0\),流量为\(1\)的边。然后跑费用流,这样能找到答案了,边数是\(nk\),点数为\(o(n)\)。玄学网络流应该能过。

总结:遇到只能匹配几次的问题,可以让流量为几,然后贡献作为费用,最后跑费用流;如果一个点有好多个相同边权的出边,可以看这些出边的出点是否是连续的考虑是否能够优化建边。

代码源/qoj17177

这个有一个转化场上想到了。就是没有完全匹配上的\(i\),他们的\(b_i\)一定会组成若干个连续段,并且每个连续段对应的\(a_i\)的最小值就是这个连续段的最小值。但是这个结论太丑了,根本没办法往下做。一个优美的转化是,每个\([a_i,b_i]\)之间的数一定至少存在有一个。那么这个就等价于\(\cup [a_i,b_i]\subseteq \left\{b_i\right\}\),但是又因为\([a_i,b_i]\)中一定存在\(b_i\),所以\(\left\{b_i\right\}\subseteq \cup[a_i,b_i]\),所以\(\cup [a_i,b_i]=\left\{b_i\right\}\)。那我们就转化成了集合之间判相等。那又因为\(b_i\in[a_i,b_i]\),所以只需要判断集合大小就行了。那把\(a_i,b_i\)看作先端短点,那就变成区间线段的并。这个用珂朵莉树维护。剩下的就简单了。

AT_arc156_f [ARC156F] Make Same Set

这个题暴力应该能用费用流,但是太暴力了,复杂度太高了,所以要写网络流。

首先这个题是可以转化成匹配问题的,就是第一种选法和第二种选法他们共有的权值进行匹配。费用流就是第一种方式的点在左部点,权值在中间,第二种方式在右部点,然后方式与能连的权值连一起。然后呢,网络流与他图练法一样。首先一个假做法是直接跑网络流,此时可能有的点对应的中间点的流量都为零,也就是没选,这是不合法的,称这些点为待选点。这种做法适用于选\(a/b\)或不选。我们希望最终的图是不存在待选点的,所以我们考虑一开始先通过某种方式流一下,使图上没有待选点,然后再多次增广,保证每次增广的时候不会出现待选点。如何保证。待选点出现的时候就
说明有中间点的流量变为了\(0\),就说,有右部点通过中间点再走到了左部点,我们成新出现的待选点是\(i\)(假设在左部点),通过的中间点为\(j\),因为\(i\)是待选点,所以\(i\)和谁都没有流量,所以我们就可以通过\(i\to j\to\cdots\),进行增广,避免了出现待选点。这样的路径特征是什么呢?短,就是比出现待选点的路径要短。并且只要有待选点就能继续短下去,所以只需要找最短路增广就行了。那\(dinic\)本来就是找最短路进行增广,所以就直接做了。而一开始的时候怎么保证没有待选点呢?只需要让\(a_i\)这个中间点有流经过就行了,这样每个左右部点不是待选点了。那就好了

暴力好打;不同方式构造出相同的集合,可以通过匹配的思想转化题意;想要让一个状态避免出现,可以先构造没有这个状态的东西,然后保证在后面的操作中不出现新的这样的状态就好了。

写的时候真是糖丸了。1.修改中间点之间的路径时,下标应当用离散化后\(a_i\),而不是\(i\),2.输出是要输出离散化之前的东西。

F - Constant Sum Subsequence

这个暴力的想就是设\(f_{i}\)表示把所有\(i\)的数的划分都找出来最短需要\(f_i\)的长度,然后就枚举一个\(x\)\(nxt(f_i,x)\)贡献到\(f_{i+x}\)\(f_{i,x}\)\(\max\),因为要满足所有的。\(nxt(f_i,x)\)表示\(f_i\)后面第一个\(x\)的位置。直接做\(O(S^2\log^2 S)\)的。肯定过不了。这时我们向分治去\(N\)\(l,r\)分成两半,左边自己贡献完后给右边贡献然后右边再自己贡献。但是复杂度没变啊。这时候就需要性质了,\(f_i\)一定是单调不降的很显然,那么如果\(nxt(f_i,x)\)还没有\(f_mid\)大,那他转移过去一定没有意义,因为不如用\(f_mid\)转移。因为不管怎么说\(nxt(f_{mid},i+x-mid)\)一定大于\(nxt(f_i,x)\)。所以我们只进行贡献\(nxt(f_i,x)\ge mxt(f_mid,x)\)这些值。但显然只能等于。所以就是找到\(mid\)前面第一个\(x\)的位置\(pos\),然后找到第一个大于\(pos\)\(f_i\),将\(nxt(f_{i\sim mid})=nxt(f_mid,x)\)贡献到\(i+x\sim mid+x\)上,因为加的是一样的,所以可以直接用数据结构维护一下。这样复杂度就到了\(O(S\log^2 S)\)了,可过。

总结:遇到转移是单项的,我们可以考虑分治去做,一般需要再寻找一些性质,如单调性。

Spoonerisms

这个就是因为总长比较小,然后题目的意思就是,\(A\)的前缀加上\(B\)的后缀能得到一个串,\(B\)的前缀与\(A\)的后缀也能。那我们把所有串的前缀放左部点,后缀右部点,前后缀连边,如果出现了四元环就满足,所以问题转化成四元环计数。

怎么计:枚举四元环度数最大的点,找一条出边再找一条出边后标记节点,如果碰到已经标记的就是找到了。复杂度怎么分析。我们对第一次出边到达的节点进行统计、所有点都遍历他的出边的复杂度是\(O(N)\),现在要找到第一次出边到达的点\(u\)被遍历的次数是多上就行了。发现一定\(\le\min(\sum{i}[deg_i\ge deg_u],deg_u)\),如果\(deg_u>\sqrt{n}\),那比他大的一定不超过\(\sqrt{n}\)个应为度数总共是\(O(n)\),如果小,那\(\min\)就是 \(\sqrt{n}\)。所以最多遍历\(\sqrt{n}\)个,那复杂度就是\(O(n\sqrt{n})\)了。

qoj406

暴力就是对每个三明治钦定他先拿,然后建立出依赖关系,就是如果先拿他必须先拿谁,如果发现有环就不行,没环的化就找经过了多少个本质不同的三明治才停下。爆了。然后就是发现,处于上方的三明治一定依赖这个格子上方的三明治都拿走,也就是依靠上面格子中上方的三明治要先拿走,因为上方格子的下方不能先拿走,还有他自己再垫着。那么得到什么结论呢?如果钦定了是先拿这个格子上面的三明治,那么肯定要先拿左或右和上面的,然后上方的就和维护他自己时走的路径一样的,所以答案只需要加上左右走得到的本质不同的三明治就行了。那环呢?我们发现环最多再两种情况出现,在这样建图过程中,一个格子中的两个三明治都要先拿走,说白了就是自己依靠自己。第二种是向左右拓展的时候发现碰到了自己的来时路,也是自己指向自己,但是两次所指向的三明治是相同的。这两个都能维护,用两个bool数组维护。AT-hoc题我没招了。。。。

注意:在维护第二种环的时候,部分写法(我的)需要先把起点加入bool数组里,否则要调半天。

qoj8800

这个题用到了竞赛图的知识,具体来说就是兰道定理。
首先这道题建出来边就是一个竞赛图,因为是竞赛图,所以有一个优美的性质,就是缩完点后,强连通分量组成了一条链,并且拓扑序小的强连通分量的出边一定指向拓扑序更大的强连通分俩姑娘。所以判断是否支配就是说判断是否在同一个强连通分量里,或者谁的拓扑序更小。根据兰道定理我们能知道将出度\(p\)从小到大排序,满足\(\sum_{j=1}^{i}p_j=\binom{i}{2}\)的个数是强连通分量数,并且满足这样的\(j\)和上一个满足这个式子的\(j'\)\(p[j'\sim j]\)所对应的原图的点构成了一个强连通分量,并且,满足按照这样找出来的强连通分量在原图的拓扑序递减。很优美的性质!!那么我们只需要找每个点的出度就行了。这个就是做四个三维偏序就行了,比较简单。

总结:像这样\(1\sim n\)之间每个点都会有唯一一条有向边的图也就是竞赛图,有很多好的性质,方便解题,所以要辨认出来。性质:缩点后成一条链,拓扑序小的向拓扑序大的分量连边;拓扑序小的强连通分量中点的出度严格大于拓扑序大的强连通分量中点的出度;兰道定理。

AT_agc035_d

最后的数一定是\(a_1,a_n\)为基础,将其他数加到这上面就是了。所以我们转向考虑求其他的数一共贡献了多少次。我们考虑,一个数累加到答案的次数与其旁边的两个数累加到答案的次数有关,所以我们统计的时候肯定就只能找连续的三个数了。不知道怎么想到的,就是倒着考虑,最后一个删的数\(x\)相当于与\(1,n\)连着,所以贡献次数就是\(1+1\),倒数第二个可能再\(1,x\)之间,也可能是\(x,n\)之间,贡献就是\(1+2\)\(2+1\)。这个启发我们找一个区间内最后一个被删的数是什么,这样他对答案贡献的次数就是左端点和右端点贡献次数的总和。然后再去找下两个区间,那么就是设\(f_{l,r,xl,xr}\)表示左端点是\(l\),次数是\(xl\),右端点是\(r\),次数是\(xr\)他们对答案的最小贡献是多少。\(f_{l,r,xl,xr}=\min(f_{l,k,xl,xl+xr},f_{k,r,xl+xr,xr})\)。但是数组开不下,因为次数最大值应该是斐波那契数列。所以使用记忆化,那复杂度呢?我们设\(T(n)\)为区间长度为\(n\)所需的时间是多少,\(T(n)=\sum_{T(i)+T(n-i)}=2\sum_{T(i)}\)。然后我不会算了。但是结论是\(T(n)\)应当是\(3^n\)次方级别。但是\(n\)\(18\),不过因为\(a_1,a_n\)一定不删,所以实际上长度是\(16\),所以\(3^n\)就过了。

总结:正难则反,正着想不太好想的时候应该反过来想,尤其是这种一步一步操作的。还有例如Kocke也是反过来想回简单很多。

qoj7348

这个是拓扑序,还有dfs序版本,原理相同。
其实就是疯狂求组合数。首先计算一个\(g_{i,k}\)表示把\(i\)的子树删完后\(i\)的拓扑序是\(k\)的方案数,这个可做,但我做的时候有点晕。。思想就是用父亲的答案贡献给儿子,并且需要一个类似前缀和优化的东西。求出来这个后,再乘以写系数就是\(f_{i,k}\)表示\(i\)的拓扑序是\(k\)的方案数了。

总结:经典题目了,应该算是基础了。

AT_agc066_d

这个题的思路就是对着答案找性质,然后根据性质进行dp,答案有什么性质呢?性质是,在答案中,一段极长的\(ABABABABAB\),他们中的\(A\)一开始也在这个区间内。证明,因为是极长,并且满足\(A\)不相邻,所以这个段周围一定还有\(B\),形如,\(BBABABABB\)这样,如果\(A\)是从左边来的,那他会先遇到左边的\(B\),变成\(BABA\dots\),这样,其实就不需要再动了,再动就不优了,同理右边也是。那我们就证完了。所以我们在这样的极长的连续段后面进行\(dp\),就是设\(f_i\)表示让前面都是\(ABABABB\cdots BABABAB\)这样需要的最小贡献。如果\(i+1\)\(B\)的话,那\(f_i\to f_{i+1}\)。然后我们找一段极长的\(ABAB\)。但是贡献呢?我们发现这样好像没有办法统计贡献,因为\(A\)可能向右走可能向左走。暴力做复杂度就炸了。怎么办呢?我们考虑,根据高维前缀和的思想,转移几段短的和转移一段长的其实贡献是一样的。那我们就尝试贡献最短的\(ABAB\),这样有什么好处呢?就是最短的里面\(A\)走的方向是相同的。把\(A\)当作\(1\)\(B\)当作\(-1\),因为是极短的,所以所有前缀和符号相同,所以\(A\)走的方向就是相同的。那么贡献就\(O(1)\)统计了。那就做完了。

注意:最后一个连续段可能是\(ABABA\)这样的形式,因为后面没\(A\)了,所以不需要保证有\(B\)隔开了,这样\(dp\)最后的时候就有点问题,不过没关系,我们在原字符串后面加上一个\(B\)就行了。相当于强制变成\(ABABAB\)了,这样就对了。

总结:性质!性质!性质可从答案中找到。如果碰到要转移很长一段而不好做时,考虑把这么一长段拆成等价的几个小段是否能做。

P11830 [省选联考 2025] 幸运数字

分讨就完了,就是枚举一个数或一个区间中的数是否可能成为中位数。

P11833 [省选联考 2025] 推箱子

使用数据结构维护模拟的过程就行了,就是加速模拟,把几步合起来做。

CF1404C

如果只有一个询问,那就设\(f_i\)表示从起点到\(i\)的权值是多少,\(f_{i}=f_{i-1}+[f_{i-1}\ge a_i]\)其中\(a_i=i-a_i\)。但是有多组询问。我的一开始做法是离线,然后考虑向做出来的区间前面加一个数。然后考虑答案是怎么变得。但是这样会炸,因为维护的复杂度能达到\(n\log n\)。炸了。被卡了好长时间。因为我们发现\(dp\)是从前向后进行更新的,所以向后加点维护起来就变得好多了。但是我们当前状态设的是起点到\(i\)的权值,所以我们需要改变一下状态。那显然起点就变成可变的了,终点要变成固定的。所以我们令\(f_i\)表示从\(i\)为起点到现在钦定的终点的权值是多少。那先后加一个点只需要将\(f_i\ge a_i\)的值都加一就行了。然后单调性是显然的,就是\(f_i\)肯定是单减的。那就没了。

P15649 [省选联考 2026] 找寻者 / recollector

场上想到\(n^3\)但是没调出来,痛失40分,警示,考场心态一定要好。
考虑拆贡献,这个比较简单了,最终的答案就是每个点为轻儿子的概率乘上\(siz\),然后考虑如何求概率。我们想要知道概率,我们就要知道\(u\)这个儿子的重链长度,还要知道他外面的重链长度之和,所以两个\(dp\)数组就有了,\(f_{u,j}\)表示\(u\)所在子树重链长度为\(j\)的概率为多少,\(g_{u,j}\)表示与\(u\)同级的儿子重链长度总和为\(j\)的概率是多少。\(f_{u,j}\)\(f_{v,j-1}\)\(g_{v, k}\)推出。\(g_{v,j}\)本质是一个可撤销背包。详见写的另外一篇笔记。所以我们就再设一个\(h_{u,j}\)表示\(u\)的所有直接儿子重链总和为\(j\)的概率是多少。然后这个是树上背包。这部分需要注意一下,就是如果直接写循环的话,那复杂度会变成\(\sum_{v}siz_v\times pre S,pre S\)表示在\(v\)前面的儿子的\(siz\)和。这样会被卡。解决办法是什么呢,考虑每个子树的贡献,每个子树的贡献是\(siz_v\times suf S\)\(suf S\)表示从\(v\)开始,他后面的(包括他自己)的\(siz\)和,但是这个是没有保证的,只有\(siz_v\times(siz_u-siz_v)\)是有保证的。那么我们直接取出最大的儿子,把他的信息直接付给\(h\),然后其他的正常做,这样,每个子树的贡献就\(\le siz_v\times(siz_u-siz_v)\)了。这样就能过了。

这个不撤销背包的写法有点太唐了,这个相当于是填表法,复杂度可能到达\(O(n^3)\),我们只需要使用刷表法,然后滚动一下数组就可以了。

总结:可撤销背包,树上背包,\(siz_v\times(siz_u-siz_v)\)是有复杂度保证的。刷表法和填表法变化一下。

P5904 [POI 2014] HOT-Hotels 加强版

简单版,\(n^2\)是容易做的。不说。这里是加强版。这个我不会设啊。设\(f_{i,j}\)表示\(i\)子树里到\(i\)的边数为\(j\)的点个数,\(g_{i,j}\)表示\(i\)子树里面满足\(d(lca(x,y),x)=d(lca(x,y),y)=d(lca(x,y),i)+j\)\((x,y)\)个数。然后考虑转移,对于一个\(u\)来转移\(ans+=\sum{g_{u,0}},ans+=\sum_{x,y\in son(u),x\ne y}{g_{x,j}\times f_{y,j-2}}\)\(g_{i,j}+=\sum_v{g_{v,j+1}},g_{i,j}+=\sum_{x,y\in son(u),x\ne y}{f_{x,j-1}\times f_{y,j-1}}\)\(f_{i,j}+=\sum_{v,j-1}\)。发下这个过程可以优化,就是类似于前缀和的内阁样子,那就做到\(O(n^2)\)了,然后呢,接下来就是长链剖分就优化到\(O(n)\)了。然后就没了。

注意:因为\(g_{j}\leftarrow g_{j+1}\),所以指针要指向前面,也就是\(g_{hson_u}=g_{u}-1\),所以要保证\(g_u\)前面有\(dep[u]\)个内存,但是又因为我们还要访问\(g_{dep_u}\),所以还要保证后面又\(dep_u\)的内存,所以就需要开两倍内存。

总结:遇到三个点两两路径之间的交点,然后对这三个点统计答案的话,不一定只能在交点处进行统计,也可以在中间点枚举。在交点处统计可能需要写换根\(dp\),并且可能没法优化,但是在中间点统计,记录一些辅助数组,然后进行统计,可能会好一些。

P14363 [CSP-S 2025] 谐音替换

这个转化有点太天才了。就是考虑\(s1,s2\),他们前缀最长相同是\(a\),后缀最长是\(b\),不同的是\(x,y\)。对于一个\(t1,t2\),类似的,有\(at,bt,xt,yt\),能替换是什么,\(xt=x,yt=y\),并且\(at\)\(a\)的后缀,\(bt\)\(b\)的前缀,所以其实就是找到xt,yt\(和\)x,y\(位置,然后如果相同,就暴力向外匹配,能匹配成功就行。这时场上的思路,不会做了。那么怎么办呢?发现一个必要条件为\)at+xt+yt+bt\in a+x+y+b\(。但是这样是不充分的,因为即使匹配的时候,\)xt+yt\(和\)x,y\(可能是不对齐的,那么为了使他对齐,我们就引入特殊字符,即变成\)at+?+xt+yt+?+bt\in a+?+x+y+?+b$,那这样就是充要了,然后就可以用AC自动机了。但是还有一个问题,匹配后要找到根链上的权值之和,但是不能直接维护到根链的权值和,因为这样计算的就是出现次数而不是出现的种类数的。但是呢,因为我们加入了特殊字符,所以这个题比较特殊,所以这个个数就是种类了,所以复杂度就对了。

总结:匹配时可以添加特殊字符使得匹配的位置限制在某个特殊的位置。

P15650 [省选联考 2026] 摩卡串 / string

这个是一个增量构造的过程。首先考虑一个怎么样的串严格比\(S\)小,可以分为两种1. 是\(S\)的真前缀2. 是\(S\)的一个真前缀+0+任意,并且\(0\)这个位置在\(S\)应当是\(1\)。那么我们从一个空字符串\(t\)开始向后加字符,第一种字符是好统计的,我们只需要记录没加这个字符的时候最长的\(t\)\(S\)的一段前缀的相同的后缀是什么,也就是相当于在做\(kmp\)匹配。然后就跳\(nxt\)树判断有多少个能够匹配。第二种情况呢?直接统计是不太好的,但是我们其实可以钦定加的这个字符就是第二种情况的\(0\)的位置,也就是加的一定是\(0\),这样,再向后加的时候这个位置就一定会产生贡献,所以我们只需要记录在加这个字符之前,\(t\)中有多少个第二种情况的字符串,然后累加就行了。然后我们要求的是最短的,然后就用最短路(这太神仙了。也就是用\(BFS\)就行。注意,还有\(S\)必须是\(t\)的子集的限制,这个我们需要在转移也就是\(dp\)过程中再加一个状态表示当前\(t\)是否已经包含了\(S\),当最长的后缀长度到达了\(n\)就说明有\(S\)了。
详细的:\(BFS(len,c,g,f)\)代表最长的匹配长度,第二种情况的个数,严格小于\(S\)的个数,是否包含了\(S\),从\((0,0,0,0)BFS\)\((\sim,\sim,k,1)\)。但是这样是\(n\times k\times k\)的。好像会爆。不过我们考虑,如果现在有\(c\)个第二种情况的,那么必定会有\(\frac{c(c+1)}{2}\)个小于\(S\)的字符串。所以\(c\le\sqrt{k}\),所以就能过了。

注意:因为是真前缀,所以如果\(t\)有与\(S\)相等的一个后缀,那么就要减去他的贡献。

总结:1.关于数量限制的可以采用增量构造的方法;2.\(dp\)也是一种图把,所以要找最小的答案是可以往最短路的方向去想;3.严格小于一个字符串有两种情况:1. 一个真前缀,2.真前缀后接一个比原来位置小的然后随意。

P15653

这个是个构造题,有点复杂了,前置知识是欧拉路径。具体在\(oiwiki\)或写的笔记;
他都写了\(p\ge \frac{n(n-1)}{2}\)。所以大概率次数就是\(\frac{n(n-1)}{2}\)。先不管这个。首先转化一下题意,这个题的操作相当于是\(\oplus 1\),把输入的边不存,存下没输入的边,这样问题就转化成了剩下的边最少。首先我们可以通过操作异或出来一个偶数元元环,具体的,如果我们想异或出来一个四元环\(a-b-c-d-a\),那么可以进行四次操作:

\[\begin{aligned}\newline (a,b,x_1,x_2,\dots,x_{k-1})\newline (b,c,x_1,x_2,\dots,x_{k-1})\newline (c,d,x_1,x_2,\dots,x_{k-1})\newline (d,a,x_1,x_2,\dots,x_{k-1}) \end{aligned} \]

这样就能在不影响其他边的情况下构造出四元环了。有了四元环,我们可以做什么,定理是,如果一个图是欧拉图并且边数为偶数,那么就可以通过四元环的方法把这个图都消去,具体的,\(a-b-c-d-e-f\),那么就可以消去\(1-a-b-c-1\),这样就变成了\(1-c-d-e-f\),相当于消去了两条边,所以就结束了。那么第一个问题其实就是求,至少修改几条边的状态也就是保留几条边,然后才能使得当前状态变得能够达到最终状态。我们令\(A=\oplus_{x\in E}x_i\)\(x_i\)表示每个边的状态\(0/1\),那么一次操作就相当于异或\(\binom{k}{2}\)\(1\),也就是与\(\binom{k}{2}\)的奇偶性相关。令\(A'\)表示最终答案的值,那么如果\(\binom{k}{2}\equiv 0\),那么\(A\)\(A'\)的奇偶性就要求相同。那么我们把最终剩下来的边在\(A\)\(A'\)中都异或掉,那么\(A'=0\)\(A\)就相当于修改一些边的状态后的\(A\),那么\(A\)就要保证是\(0\),也就是说边数要是偶数。同理对于每个点\(u\)来说,我们定义\(U=\oplus_{x\in to(u)}x_i,x_i\)就是\(u\)出边的状态。如果一次操作中,操作到了\(u\),那么相当于异或\(k-1\)\(1\),也就是\(U\)的变化与\(k-1\)的奇偶性有关。同理,我们能得到,当\(k-1\equiv 0\)时,\(U=0\)。所以,当\(\binom{k}{2}\)\({k-1}\)的奇偶性不同时,我们需要修改的边的就不同,一下进行分讨:

\[\binom{k}{2}\equiv 0,\text{那么必须要修改边使得边数最终变成偶数,否则就不管边数} \]

具体的,我们只需要选择一条边修改状态就行了,然后把答案--。不管是原来是\(0/1\)都可以。因为最终都变成\(0\),所以实际上,他的状态和它本来的状态就是不同的,也就是被保留下来了。

\[(k-1)\equiv 0,\text{那么必须修改点使得点度数都变成偶数,否则就不管点度数} \]

具体的,因为图的总度数一定是偶数,所以我们只需要找奇度的点两两配对就行了。
更精简的,我们可以按照\(k%4\)进行分类,在不同的数下面有不同的修改边的方式,特别说一下\(k%4=1\)的情况,这个把点改成偶数点后,边如果还是奇数,就不能随便改了,这时只能改一个奇数环,才能不影响点的奇偶性,所以我们尽量少的改就是三元环。然后如果有奇数点,那么可以和奇数点一起改三元环。
这样,我们就得到了理论上第一问的最大值,也就是满足上面的条件只是必要条件,而不是充分条件,我们要在构造过程中证明充分性。
现在我们先考虑当\(\binom{k}{2}\equiv 1\)时,怎么通过操作把边数改成偶数。那其实操作一次就行了,因为操作一次会改变边的奇偶性
\((k-1)\equiv 1\)时,我们考虑怎么把奇度点改为偶度点,因为要保证其他点和与他无关边状态都不改变,所以我们需要异或两次,所以我们找一对点,那么就是\((u,x_1,\dots,x_{k-1}),(v,x_1,\dots,x_{k-1})\)这样就行了。

现在继续考虑,当\(n>k+2\)时,我们考虑将\(n-1\)变成子问题,(至于为什么是\(k+2\),下面解释)那么就是考虑把\(n\)的连边都删掉,根据刚才把奇数点改成偶数点,我们可以这样,选两个有连边的点\(u,v\),\((n,u,x_1,\dots,x_{k-2}),(n,v,x_1,\dots,x_{k-2})\)但是如果有奇数个连边的点呢?这种情况只会在\(k-1\equiv 1\)的情况出现,所以我们直接选择一个有连边的点,然后其他的随便找一些点,然后把这个边消了。会影响已经满足的性质吗?实际上是不会的,这个比较简单不说。这样就保证了在\(n-1\)次内删掉\(n\)了,这样我们就能够放心的做子问题了。
那么就到了\(n=k+2\)的情况了,现在我们就要操作把点度数都变成偶数,边数变成偶数,然后找欧拉回路通过四元环删边了。但是现在问题是操作数呢?我们注意到同一个操作进行两次是没必要的,然后当\(n=k+2\)是,又只会有\(\binom{n}{2}\)个操作,所以操作数就对了。那么这道题就没了;

总结:欧拉图的性质和欧拉回路的构造需要掌握;构造题找不变性来证明正确性或必要性或充分性,具体的是构造一个函数,然后观察这个函数在操作前后的变化来找到性质,例如这道题就是找所有的异或和。 \(k-1\)\(\binom{k}{2}\)的奇偶性通过\(k%4\)分类。

P4768 [NOI2018] 归程

这个要说的只有,离散化的时候要判断好要排序的区间是啥,不要习惯性的写上了\(n\),很sb。

CF888G Xor-MST

这个题的思路比较好,但是我没想到。就是回忆写最小生成树的过程,找出最短的边来,然后判断联不联通,加不加边。考虑现在呢?因为要异或,所以我们考虑建出来一个\(01tire\),然后考虑,如果一个点\(u\),其\(ls_u,rs_u\)中的点已经联通了,那么考虑如何把\(ls_u\)\(rs_u\)这两个连通块连起来。两种方式:1. 选择两个\(ls_u,rs_u\)内部点联通。2. 选择一个外部点,分别联通\(ls_u,rs_u\)。第二种情况一定比第一种情况劣,因为相当于他们的\(LCA\)在更高的地方,异或出来的值就会更大。所以我们就说明了一个点其子树之中的点是通过自身内部进行联通的,那么就可以写了。具体的,对于一个点,如果有左右儿子的话,选择一个较小的子树,然后暴力取出里面的数,在另一个子树里找异或最小,然后就行了。复杂度应该是\(O(n\log^2 n)\)

CF986F Oppa Funcan Style Remastered

这个前面都能转化,就是转换成\(k\)的质因子之和能不能表示出来\(n\)。然后首先质因子个数不超过\(\log n\)个,这个是显然的(但是我没注意到)。然后我们可以这样,在\(mod k\)意义下求同余最短路,但是这样点数太多了。那到底怎么做呢?用最小的质因子做模数就可以了。如果一个数有大于两个质因数的话,那么小的内阁就一定小于\(\sqrt[3]{n}\),对于这道题就是\(1e5\)个,所有点数和边数就对了。那么就能做了。其他的情况特判就可以。

总结:这道题卡住我的地方1. 小的质因数要小于\(\sqrt[3]{n}\),2. 同余最短路可以用较小的模数来缩减点数

P10779 BZOJ4316 小 C 的独立集

不要把小于等于写成小于。

然后就是说,这个就是建出圆方树来然后跑\(dp\)就行了。然后设\(f_{u,0/1}\)表示这个点的父亲节点选不选,这个是比较套路的设法,所以就不说了。不过这个复杂度是\(O(n)\)的,但是给\(5e4\)就很奇怪。

静态仙人掌P4244 [SHOI2008] 仙人掌图 II

这两个和上面的内道题其实是一个题。都是建出来圆方树然后做一些东西。

P9869 [NOIP2023] 三值逻辑

这个有点困难。就是首先我们能找到直接支配的东西,例如,\(1\)必须和\(2\)不同什么的。这种情况我们给\(1,2\)\(1\)的边,否则连\(0\)的边。所以我们相当于找到了一张图。我们要求什么呢?我们要求不能有一个环上每一条边异或起来是\(1\)。这个好判断,我们 \(dfs\)一下就行了。
总结:像这样,有不断地连着的限制关系的,那么我们可以通过找到最后的直接联系来建边找限制。

机器人

这个看着还挺吓人的,但其实不困难。我们发现,其实本质不同的状态数一共只有边数种,所以我们可以直接把一个点拆成若干个状态,然后再原图上跑最短路就行了。正确性分析和原来的是一样的。所以就行了。

AT_abc450_f [ABC450F] Strongly Connected 2

这个使用到了P10790 [NOI2024] 树形图里学到的性质,就是建出\(dfs\)树后,点\(u\)的子树里必定有一条返祖边指向\(u\)的祖先(不包括\(u\))。那么对于这道题来说,就是说以\(n\)为根建,那么对于每个点\(u\),必须有一条\(X_i\le u,Y_i>u\)的边,所以题目就转化成了区间覆盖问题。就是每个点都要有一个合法的区间覆盖他。我们设合法的点为,点\(i\)被一条\(X\le i,Y>i\)的区间覆盖了。那我们设\(f_{i}\)表示只使用包含于\(1\sim i\)中的区间,将\(1\sim i-1\)变成合法的点。然后\(i\)被至少一条\(Y=i\)的边覆盖的方案数。答案就是\(f_n\)。考虑转移。那么我们枚举以\(i\)的线段,\(l\sim i\),然后将\(f_{l\sim i-1}\)加到\(f_{i}\)上。注意判断两个区间相等时的方案。但是发现这样假了,考虑少情况了,为什么呢?我们考虑,当我们选了一个区间\(l\sim i-1\),然后将\(x\in [l,i-1]\)贡献给答案,那么只有\(1\sim x\)中的区间和\(l\sim i\)的区间选了,其他都没选,但是考虑\(x+1\sim i-1\)中的区间,因为如果不选\(l\sim i\)这个区间,那么就不能再\(f_{x}\)的基础上选这些区间,因为一定不合法,所以\(f_{x+1\sim i-1}\)中的方案就不会包含选这个的方案。但是我们选了\(l\sim i\),所以我们就可以算这些方案,所以我们转移的时候需要把这部分答案贡献进去。

总结:考虑方案数的时候,要把所有可能合法的情况都贡献到,也就是,写转移之前先考虑一下这样转移是否可以不重不漏的转移完。注意选择一个东西使得原来不合法的状态变得合法的方案数。

P10790 [NOI2024] 树形图

额,因为要找到\(1,2\)类点。由于\(1,2\)类点的定义,我们能知道,他们一定只存在于缩点后入度为\(0\)的强连通分量里,并且如果有两个及以上入度为\(0\)的强连通分量,那么就都是\(3\)。这时特判一下就行了。然后我们考虑,如果第一个强连通分量里面没有\(1\)类点,那么所有还在强连通分量里面的点都是\(2\)类点吗?答案是可以的。我们考虑,没有\(1\)类点的限制其实就是相当于没有必须不能删掉的边,又因为\(2\)类点是由两条路径,那么我们把两条路径分岔开的路径部分删去最后一条边,这样每个点的可达性没有变,但是路径条数减少,所以一定能够变成\(1\)类点。
那么我们接下来考虑有至少一个\(1\)类点的情况。那么我们考虑,因为有一类点,所以入度为\(0\)的强连通分量里的点到其他强连通分量里的点方案数只有\(1\)。所以只需要再入度为\(0\)的强连通分量里考虑。那么我们就把其他所有点都删掉。我们以一个一类点为 根,然后建出\(dfs\)树。这样,如果一个点\(u\)被两个及以上的返祖边覆盖了(设其为\(X\to Y\),被覆盖说的是\(X\in son(u), Y\in \text{祖先}(u)\))。那么就一定存在两条路径到达\(fa_u\),所以他不是\(1\)类点。如果恰好有一条\(X\to Y\)。那么考虑若\(Y\)\(1\)类点,那么\(X\)也是\(1\)类点,也为他子树里的点只能通过树边到达,因为是简单路径。然后其他的点只能通过\(Y\)到达,因为\(Y\)\(1\)类点,所以\(X\)到其他点也只有一条路径,所以\(X\)就是\(1\)类点。反之,如果\(Y\)不是一类点,那么\(X\)也不是。那么一类点就处理完了。

二类点:依旧顺着这个思路。首先我们确定了\(1\)类点,那么覆盖这些一类点的返祖边是一定不能删除的。那么考虑判断一个不是\(1\)类点的点是否是\(2\)类点。首先如果有两条及以上不能删除的覆盖他的返祖边,那么他一定不是。其次,如果只有一条\(X\to Y\),那么就删掉其他的,判断\(Y\)是否是\(1/2\)类点,因为首先如果\(Y\)\(1\),那么根据\(1\)类点的求法,我们知道删除了这些边以后\(u\)也是\(1\)类点。如果\(Y\)\(2\),那么我们可以先删一些边,把\(Y\)变成\(1\)类点,并且这些边里面一定没有\(X\to Y\),因为不覆盖\(Y\)。所以这时也就和刚刚一样了。最后,如果一个不可删除的边也没有,那么我们就查看是否有一条覆盖\(u\)的返祖边指向的点是\(1/2\)类点。证法和刚刚一样。那么二类点也没有了。

最后,因为我们这个是以\(1\)类点为根的基础上。所以我们还要求出来一个一类点。求法。我们考虑在\(1\)类点为根的\(dfs\)树上,叶子节点的度数一定为\(1\),我们从这里出发,如果有一个点入度为\(1\),那么我们就把这个点和指向它的点合并,就是把他的出边给指向它的点。然后删去自环。我们考虑这个操作到底在做什么。找到一个入度为\(1\)的点,然后把他和指向它的点合并说明,如果想经过这个点,那么一定要先经过指向它的点。然后删去自环呢?实际上是在满足简单路径的限制,因为不能走重复的,所以从指向它的点走到他然后再走回来是不合法的,所以就删掉。最后,如果因为没有度数为\(1\)的点但点数大于\(1\)。那么一个点到另一个点,至少有两条路径,因为本身强连通,所以一个点能到达指向另一个点的两个入点。所以就没有一类点。如果最后只剩下一个点,那么这个点就是\(1\)类点了。

找二类点的操作我不会。我们考虑,只有当一条必须被删除的边也不覆盖的时候,我们才需要找到一条合法的边。但是,如果我们再所有边里找合法的边,那是十分困难的,于是我们思考能不能只放合法的边然后判断这些边是否覆盖呢?考虑,一条合法的边一定是从孩子节点指向其祖先节点的,而祖先节点有哪些合法我们是知道了,也就是我们只需要判断,子树里有没有指向合法祖先的边就行了。那,当我们判断出了一个点如果合法,那么我们把以他为终点的返祖边放到起点所对应的节点上,然后我们查询的时候只需要判断子树里是否有点有贡献就行了。这个使用树状数组维护即可。具体的,如果判断出一个点\(v\)合法,然后找到所有\(u\to v\)的返祖边,将树状数组里\(u+1\),就行了。

另外一个事情。这道题能建出来一棵没有横叉边的dfs树的前提就是以\(1\)类点为根,因为到其他点路径唯一,否则就不能保证有这个性质了。

那么这道题就完了。思维量和代码难度都挺大的。我还没写出来。

化学课

这个使用了欧拉序优化LCA。

赛车问题

这个的做法没见过。如果我们要合并两个连通块并且要记录他们的直径。对于这道题来说,我们知道两个连通块的直径的两个端点,那么我们就能知道合并后直径长度并且记录下端点。这道题暴力就是说对于一个点\(v\),找到所有包含他的区间,然后这些区间对应的边连起来组成的各个连通快的直径的最大值。这里是简单地。但是我们发现直接做是\(O(n^2)\)的。这道题采用了线段树分治和可撤销并查集。建一颗以速度为子节点的线段树,然后把\(l,r\)区间上覆盖其对应的边,只覆盖线段树上\(logn\)个区间,这样,从根到一个点\([v,v]\)所用的所有边,就是包含\(v\)的所有边了。然后回溯的时候就撤销。然后没了。

总结:看到一个连续的区间可以考虑把他拆开,可以是根号,可以是线段树;可撤销并查集。要会。

CF1707D

考虑一个点什么时候能删,就是其子树里只剩下一个子树或没有子树,而\(1\)就是没有子树的时候才能删。那么我们设\(f_{i,k}\)表示\(i\)子树里使用\(k\)次删完,然后每次删除一个非空集。但是这样不太能转移,因为无法保证转移的时候不会出现空集。我也就再这里挂了。那么如果无法保证没有空集,就有空集这样做,发现最后可以容斥。因为如果我们设有空集的方案数为\(f_i\)那么有\(f_{i}=\sum_{j=1}^{i}\binom{i}{j}ans_j\)。然后就可以二项式反演了。考虑\(f_i\)怎么求。那么设\(f_{i,k}\)表示\(k\)次删完但是可以删空集的方案数。此时我们又发现一个事情就是如果但是这样定义,那么一个方案可能会被两个\(k\)记录,就是说一个没有空集的操作相同然后空集的位置也相同的方案被两个地方记录了,我们不期望有这样的事情发生,所以我们加一点限制,就是说\(f_{i,k}\)表示\(k\)次删完并且最后一次删的时候不是空集的方案数,这样就行了。考虑转移。对于一个非\(1\)节点,删掉这个节点的方案有两个,1.把子树删完。2.删掉只剩下一个子树。对于\(1\)来说,我们只需要把子树的操作放到\(j\)个里面,也就是\(f_{u,j}=\prod(\sum_{k=1}^{j} f_{v,k})\),不需要乘组合数的原因是因为有空格,所以组合数所带来的新方案一定会在后面看到。但是这个里面的会发现,最后的操作可能是空集。不过因为根节点一定是最后操作,所以最后操作就是删掉根节点。第二个操作。我们只需要枚举最后删的子树\(v\),因为根节点不是最后删的所以不能放到最后一个操作,也就是操作都在\(j\)之前,此时我们需要保证其他的都在根之前删完,假设我们把根放到\(k\)删掉,那么除了钦定的这个子树之外的子树的贡献就是\(\prod_{x!=v}(\sum_{z=1}^{k} f_{x, z})\)。然后还需要乘上\(f_{v,j}\)。这样保证了最后操作一定不是空集。那么就转移完了。这个东西用前缀和优化一下就行了。\(1\)就没有第二个操作。因为\(f\)的定义改了,那么\(f_{i}\)关于\(ans_i\)的递推式有没有改变呢?没有,因为\(1\)最后一定放在最后一个操作,并且实际上\(1\)是不删的,所以最终的操作序列里没有\(1\),所以除\(1\)之外的操作构成的序列是可以让最后一个操作是空集的。

需要注意的是:第二个操作贡献的时候,相当于是枚举根是第几个删的,然后把其他操作放到前面去,所以不需要考虑操作序列距离\(j\)之间有几个空集。\(\sum f_{v,k}\)这个的含义是操作次数小于等于\(j\)的方案数总和。

总结:当发现不能转移的时候,考虑是什么导致的,然后考虑去掉这个因素是否能转移,并且是否能够被容斥掉。计数和容斥 太差了。

CF1523F Favorite Game

首先能想到我们一定只会在任务点和传送门的位置,有一个没有注意到的点是当身处任务点的位置时,他所需要的时间一定\(\le t_i\),因为如果没有贡献就不会来这里,然后我们一定会在这里等着直到拿到这个任务的贡献的话,因为如果能走到别的地方再回来也能拿到贡献的话,那么我们先去别的地方然后再回来一定不劣。设\(f_{S,i,j}\)表示点亮的传送点集合为\(S\),然后当前位于第\(i\)个位置(传送点和任务点都是位置),拿到了\(j\)个贡献所需要的最小时间。然后发现空间就爆了。然后就无法向下进行了。接着来到核心的部分:在一定情况下剩下一些状态,然后互相转移。我们发现,如果我们现在位于传送点集合,由于是瞬间转移,所以我们没必要知道到底位于那个传送点,也就是位置这一维可以省去,就变成了\(f_{S,j}\)表示点亮了\(S\),然后有\(j\)个任务完成了,所需要的最小时间。接下来我们考虑再任务点上。由于一开始提到的性质,我们可以认为在任务点的时候的时间就是\(t_i\),所以\(f\)里面记录的就没用了,那么我们考虑把一个状态放到记录里面,发现只能放完成任务数,那么就变成了\(f_{S,i}\)表示点亮了\(S\),在\(i\),最多完成的任务数是多少。那么就挺对的。转移感觉也有点问题,我没想到。我们只需要进行四个之间的转移,1.传送点到传送点,2.传送点到任务点,3.任务点到传送点,4.任务点到任务点。考虑怎么转移是对的。下面把在传送点的称为\(f_{S,j}\)。在任务点的叫做\(g_{S,j}\)。考虑转移顺序,1. \(f_{S,j}\to f_{S ^ (1 << x), j}\),所以\(S\le (S ^ (1 << x))\)。4. \(g_{S,j}\to g_{S, x}\),因为我们按照时间顺序排了序,所以\(x>j\)。2. 这个就要让\(1\)最先转移了。3. 这个同样能得到\(S\)的大小关系。综上,我们只要\(S\)从小到大转移,\(j\)从小到大转移,先进行\(1,2\)在进行\(3,4\)就行了。

注意:\(g\)也要初始化,初始化成\(-inf\),因为如果初始化成\(0\),那么\(f_{x,g_{s,i}}\)这时会有错误的更新,产生"更优"的解法。(还是好好初始化把,不偷工减料了。

总结:如果状态数特别多的时候,考虑是否有特殊情况能够减少状态,并且查看这些情况是否能够包含全集或剩下的好处理,来减小复杂度。一般用于优化。

qoj13235赢家

这个是计数的好题。考虑正难则反。我们考虑,设\(1\)的可达集为\(S\)\(2\)的为\(T\),那么不能见面就是说\(S\cap T=\emptyset\)。那么容易知道\(S\)\(T\)之间没有边。因为有的话就有交集了。并且所有不在\(S\cup T\)中的顶点如果有与\(S,T\)的边,那么方向一定是指向其\(S,T\)的也就是方向确定,否则就不满足可达集了。对于\(S\cup T\)外的集合的那些点他们之间的边是不关心的,因为不会影响可达性,所以他们的复杂度只需要乘上\(2\)的次幂就行了。那么方案数怎么计算。设\(f_{S}\)表示从\(1\)开始的可达集为\(S\)(只考虑\(S\)的导出子图里面的边的方向,否则后面会算重)的方案数。\(g_{S}\)就是\(2\)的,\(cnt[S]\)表示集合为\(S\)之中的边的个数,那么方案数就是\(f_{S}\times g_{T}\times 2^{cnt_{U\(S\cup T)}}\),其中\(S\cap T=\emptyset, S,T\)之间没有连边。这时\(3^n\)的。现在考虑\(f_S\)怎么求。首先发现不能直接枚举一个子集\(T\),然后看\(T,S\T\)之间连边乘\(2\)的次幂,因为也会算重。这里我们继续考虑反过来做。找到不行的。也就是\(S\)中有部分能到,有部分到不了。那么就是设\(T\)是能到达的,\(S\T\)是不能到达的。那首先前者的方案是\(f_T\)没问题,然后由于不能到达,所以\(T\)\(S\T\)之间的边都指向\(T\),然后\(S\T\)里面的边随便了,所以方案也能算了,这个也是\(O(3^n)\)

总结:这个题卡住我的地方是我一直在想在简单路径上怎么容斥而放弃思考别的思路,所以告诉我们一个思路没什么头绪时找另外的思路,把题意进行转化,例如这个转化成了\(1,2\)可达集有交进而转化成无交;正难则反;关于两个点可达集,注意两个可达集之间的关系是什么;

P4434 [COCI 2017/2018 #2] ​​Usmjeri

这个容易想到的是就是先判断合不合法,然后再判断连通块的个数就行了。主要是判合法和如何判断连通块。首先我们可以把边放到下面的点上,然后\(0\)代表向下指,\(1\)代表向上指,对于\(x,y\),设他们\(lca\)。先说\(lca\ne x,lca\ne y\)那么就是让\(x\to lca\)\(0\)的合并,\(1\)的合并,\(y\to lca\)同理,然后就是\(x0,y1\)合并,\(x1,y0\)合并。如果\(lca\)是其中一个就没事了。然后连通块同理。而合并一条链我们只需要找到一个并查集的最高点就行了。从最高点开始继续合并即可。没了。

总结:可拓展域并查集。合并一条链的方法:记录并查集最高点。

Operation

题意:给定一个序列,进行\(m\)次操作,可能的操作有两种,1. 询问\(l,r\)区间内的子集异或最大值2. 将一个数插到序列最后。强制在线。

就是,考虑普通给定一个区间进行异或,也就是线性基模板,我们记录每一个位上的基是谁然后贪心的找答案就行了。那么这个一个是要找一个区间,一个是要查入。就是我们考虑,区间问题一般就三个,然后这个看起来就需要扫描线。于是我们考虑固定一个右端点,然后考虑找左端点,如果是一个前缀那很好,就是直接把更新到右端点的位置的所有基记录下来然后贪心,这里有右端点只需要把每个基中最后出现的位置放到基里这样就行了,就是像HH的项链一样。这个好像是可持久化线性基。

P4151 [WC2011] 最大 XOR 和路径

这个不会。提示我们,看到异或和最大要联想到线性基(然而想到线性基也不知道怎么做)。我们考虑这道题,由于起点终点确定,并且无向图。所以考虑所有\(1,n\)之间的路径,每两个不同的路径一定会存在一个环,就是说一定会出现一段重合的然后再出现不同的部分,不同的部分和原来的位置就会出来一个环。于是,新的路径的值就是原路径异或环上的值很对啊。所以只需要找出一条路径,再把环找到其值扔到线性基里面然后就行了。

总结:1. 起点和终点的无向图路径,不同路径之间一定能构成环。2. 看到异或和想线性基。

CF1569F Palindromic Hamiltonian Path

我感觉我应该没有理解到这道题的精髓。做法是考虑把集合分成若干个偶子集合,每个集合代表一种元素,然后判断是否合法。我们考虑,把\(12\)个元素划分成若干个偶数子集的方案是\(1e5\)级别的,然后如何判断合法呢?我们考虑,从字符串中心开始,每次选两个同集合的数对判断他是否能够放到两边。暴力判断肯定不行。然后考虑每次选数对实际上是把集合分出来一个大小为\(2\)的集合。最终肯定就分成都是\(2\)的集合,然后这个可以暴力搜出来,然后判断合不合法的。于是我们先搜出来所有合法的集合大小都等于\(2\)的划分,然后把判断合不合法。如果合法就把这个方案压一下然后记忆化一下。然后进行集合划分,如果当前集合已经有判断是否合法就返回如果没有就暴力拆然后记忆化搜索。然后没了,复杂度有点高需要卡。

总结:构造回文字符串从中心开始向两边走。

P1450 [HAOI2008] 硬币购物

这个就是普通的背包然后前缀和优化一下。糖了,前缀和没想到。

P4717 【模板】快速莫比乌斯 / 沃尔什变换 (FMT / FWT)

或和异或的都比较简单,因为本质是关于集合的,拿或举例,\(F(A)_{i}=\sum_{j\subseteq i}a_i\)。这个使用高维前缀和就行。然后\(F(C)=F(A)\times F(B)\)。然后再高维差分就行了。然后与是一样的。
我们重点说一下异或。这个\(F(A)_{k}=\sum_{i=0}^{n-1}a_i\times (-1)^{popcount(i\And k)}\)。然后通过暴力拆解能得到\(F(C)=F(A)\times F(B)\)。接下来我们考虑如何求\(F(A)\)。分治。就是我们考虑把\(n\)个数分成两半,前一半后一半,就是最高位是\(0\)的和最高位是\(1\)的,我们先把后一半的最高位去掉然后求出一个\(F_2\)来。前半部分称为\(F_1\)。那么我们考虑对\(k\in[0,n-1)\),得到\(F_k=F_{1k}+F_{2k},F_{n/2+k}=F_{1k}-F{2k}\)。就是考虑\(i\And k\)的奇偶性变化,如果是前半段,那么前半段值不变,而又因为最高位为\(0\)所以后半段的与的奇偶性不变。后半段,由于前半段最高位为\(0\),所以奇偶性肯定不变,但是对于后半段多了一个\(1\),所以奇偶性就改变了,所以是要乘\(-1\)。所以递归写或递推就行。然后得到了\(F(C)\)呢。我们考虑反推,从长度为\(n/2\)开始,然后根据\(F_k=F_{1k}+F_{2k},F_{n/2+k}=F_{1k}-F{2k}\)这个式子反退出来最后一层,由于最后一层就是原数组所以我们就对了。复杂度\(O(n\log n)\)就行。

P3889 [GDOI2014] 吃

这个。考虑对于区间用扫描线、分治、莫队。然后这个要用扫描线(感觉。所以我们考虑动态的加点。我们发现,固定一个右端点\(r\),如果我们知道了\(i\)位置表示\(1\sim i\)\(i\sim r\)的答案,那么我们就查询就行了。我们考虑加进来一个点会有什么影响。就是说,因为是\(gcd\)所以我们考虑这个数的所有约数是否能对答案产生贡献。因为是\(1e5\)所以最多有\(128\)个约数。我们考虑对每一个约数来说,如果这个约数在所有数中第一次出现的位置在当前这个数之前,假设为\(j\),那么所有\(i\ge j\)\(i\)的答案都可以被更新。而查询的时候例如\(l,r\),那么我们就在插进\(r\)这个数之后查询\(l-1\)即可。所以我们要支持的操作就是区间\(max\)单点查。复杂度就是\(O(nd\log n)\)

总结:1. 区间处理想:扫描线,分治,莫队。2. 碰到\(gcd\)可以考虑约数。而我们需要关注的是在当前值域下一个数最多会出现多少约数。3. 动态开点线段树的常数比较大,所以当空间允许的时候可以不写动态开点(当需要卡常的时候)

CF578D LCS Again

我们考虑\(T\)的最后一个字符\(s\)是否在匹配中,如果没有,那么\(s\ne S_n,s\ne S_{n-1}\)。那么选择其他的一个字符,然后找到\(S\)中删去一个后本质不同的串放在前面就行了。然后这个不匹配其实还有一种情况,就是\(s=S_{n-1}\)。就是\(1\sim n-2\)不出现在前面,但是出现了一个\(S\)删掉的一个子串。我们先不考虑这种情况,先考虑在的情况。\(s=S_n\),那么方案数就是\(n-1\)的方案。\(s=S_n\And s\ne S_{n-1}\)。那么就是\(S_{1,n-2}\)出现在前面就行了,这个方案也比较好算。最后我们考虑\(s=S_{n-1}\)并且不在的情况。那么我们一定会把\(S_{n-1}+S_{n}\)放到\(s\)前面的。然后我们考虑,如果\(S_{n}=S_{n-2}\),那么我们还需要把\(S_{n-2}\)放到前面,原因和把\(S_{n-1}+S_{n}\)放到前面是一样的,因为如果想不让前面的一段前缀出现在这里就一定要这么放。于是我们找到第一个\(i\)满足\(S_{i}\ne S{i-2}\),此时\(T\)最前面两个是\(S{i-1},S{i-2}\),此时如果\(S_{i-1}\ne S{i-2}\)那么我们只需要在\(S_{1\sim i-2}\)删掉一个字符然后放在前面就行了。否则把方案减一就行了,就是相当于保证\(S_{1\sim i-3}\)不出现。

总结:有点绕,需要脑子清醒。从后往前进行考虑。

P7276 送给好友的礼物

不会。思考,暴力设\(f_{u,i,j}\)表示从\(u\)开始,\(A\)\(i\)步,\(B\)\(j\)步是否能够拿到所有苹果并回来。然后这是一个可行性\(dp\),所以我们考虑把其中一维放进去,那只能放\(j\)\(i\)一样,所以我们设\(f_{u,i}\)表示从\(i\)开始,\(A\)\(i\)步,\(B\)最少需要走几步才能拿到所有苹果并回来。那么这个就可以转移了,就是一个树上背包\(n^2\)的。然后就行了。

CF1693D Decinc Dividing

这个也是做出来了好吧。首先我们不难发现,以一个右端点结尾的所有好的子段的左端点是连续的,所以有单调性。然后所以如果我们知道了以一个左端点的最长好子段就行了。考虑如何求,设\(f_{i,0/1}\)表示\(i\)作为左端点以单调递增的形式出现还是单调递减的形式时的最长子段,然后通过分讨从后向前转移就好了。

总结:分讨时要考虑到所有情况。

AT_ddcc2017_final_d なめらかな木

这个题有点牛逼了。肯定是想要从\(1\sim n\)顺次填上的,然后呢,我们填一个数的时候只关心\(i-1\)\(i-2\)在哪里,和那些是填过的,那么我们设\(f_{i,j,k,S}\)表示填了\(i\),\(i-1,i\)分别是\(j,k\)填过\(S\)的方案数。但是直接转移爆。我们此时考虑深挖\(-2\le c_u-c_v\le 2\),这个性质有啥用。他钦定了每个点的度数最多是\(4\)。然后我们考虑,把\(j,k\)删掉后剩下最多会有\(7\)个连通块,而每个连通块不是都填了就是都没填。证明,如果填了,那么他\(\le i-2\)。如果没填,那么\(\ge i+1\),所以如果相连差值就一定\(>3\)。于是我们复杂度就降下来了\(n^3\times 2^7\)

注意:因为我们假定了树的度数小于等于\(4\)。但是如果不是的话可能就会出问题,就是\(re\),因为与删完后的连通块数有关。

总结:关注点的度数,点的度数影响着删去他后剩余的连通块数。

P9173

被黄题狙击了。就是设\(f_{l,r}\)表示填到\(a\)\(l\)\(b\)\(r\)了的最小值,然后就转移。

总结:看到数据范围猜算法,比如\(n^2\)的就先别想\(O(n)\)的,太奇怪了。

4.25 湖南集训

P7670 [JOI 2018 Final] 毒蛇越狱 / Snake Escaping

平衡复杂度的题。考虑,\(\min(num(0),num(1),num(?))\le 6\)。所以呢,我们考虑对最小值下刀。当\(?\)少的时候,那么我们暴力枚举就行了。当\(0\)比较少的时候,我们考虑,先把\(?\)都换成\(0\),然后找他的超集(高位后缀和),但是发现直接找会重,所以我们容斥一下就行了,对于\(1\),我们考虑把\(?\)替换成\(1\),然后找子集,同样容斥。我们考虑为什么\(0\)就是把\(?\)改成\(0\)\((1)\)同理。因为我们想用到比较少这个性质,如果我们找\(0\)类型的子集,那么就需要关注\(1\)的个数而不是\(0\),所以性质也就用不到,所以就要找超集。

总结:平衡复杂度,如果看到类似\(\min\le x\)这样的结构,猜一猜复杂度是否与\(x\)有关。

P9316

考虑,当所有的策略都清楚后如何求每个人的输赢的局数。二选一问题的经典做法是建图。例如这道题,每人有两个选择,那么我们就给\(x,y\)连上一条边,然后我们进行定向也就是克什么做的操作。我们定向时,要求一个点的入度不能超过\(1\),代表一个数值只能被选择一次,所以一个连通块一定是一个树或奇环树,一个树的定向方案就是点数,奇环树的方案就是\(2\),就是考虑环上有两个定向方案,而其余的树只能是外向树。所以我们就得到了第\(i\)给位置没有输的方案数,设为\(g_{i}\),那么在第\(i\)个位置胜利的方案数就是\(g_{i}-g_{i+1}\)。现在考虑原问题。由于我们要选择最优策略,所以我们肯定要贪心,如果知道后面的所有方案的好坏就好了。所以我们考虑从后向前\(dp\)。具体的,我们进行\(dfs\),每一条边就是在决策当前选的两个数是那两个数,然后我们设\(f_{S}\),表示当前整张图长得样子是\(S\)时,后面的\(A-B\)是什么。现在解释\(A,B\)。就是我们的操作序列是\(ABABABAB\)表示\(Alice,Bob\)分别操作,那么\(Alice\)赢得方案数就是所有\(A\)位置减去紧跟后面的\(B\)位置的\(g\),表示为\(A-B\),同理\(B\)类似,只是第一个\(A\)不参与。于是当我们记下了\(f_{S}=A-B\),那么最优策略就是如果当前\(A\)操作,那么他选\(A-B\)最大的,如果\(B\)就选\(A-B\)最小的,由于第一个\(A\)一定是恒定的答案,所以不影响大小关系。那么我们就决策好了。代码参考题解实现因为太不好写了。

总结:二选一问题的经典做法是建图;最优策略\(dp\)时,我们可以通过得知后面的答案然后进行决策,好像有点像\(A*?\).

posted @ 2026-02-12 15:13  lghjl  阅读(539)  评论(0)    收藏  举报