2025年代码源贵阳集训复盘-后

2025年代码源贵阳集训复盘-后

Day2 数据结构1

CF1474C

确定\(x\)后,可以逐步推导出所有数。使用一个set维护剩余数字,模拟过程并判断是否可行。

CF1237D

使用单调队列进行处理。如果队头元素大于队尾元素的两倍,则不符合条件。

P4587

通过模拟发现,设当前值域为\([1, x]\),能表示出\([1, s]\)的数,则必须存在\(s+1\)。如果不存在,则神秘数为\(s+1\);否则,将值域扩展到\([x+1, s+1]\),和变为\([1, s + sum_{x+1}^{s+1}]\)。注意到操作次数小于log(n),因此可以对每个区间暴力模拟。使用主席树维护下标区间上的值信息。

P5268

通过差分处理询问,然后使用莫队算法维护\(sum\)。拆解括号后,将每个单项式视为一个询问,每次移动只会改变一个\(cnt\)

Day3 数据结构2

CF1208D

采用倒序处理,使用线段树维护区间和。

CF1690G

对于区间类问题,使用set维护起点信息,并通过二分查找进行搜索。

CF1913D

使用动态规划(DP),设\(dp_i\)表示以\(i\)结尾的子序列的信息。通过单调栈维护前缀最小值,考虑\(dp_i\)可以从哪里转移:第一个小于\(a_i\)的数之后的点可以作为新区间被删除,还包括单调栈中的点。最终答案一定由单调栈中的点构成。

CF2000H

查询连续1的个数,类似于最大子段和问题。维护三个值:当前最大值、左侧最大值和右侧最大值。在push_up操作时合并这些值。

P7706

使用线段树维护区间信息。将表达式拆解为\(a_i - b_j\)\(a_k\),或者\(a_i\)\(-b_j + a_k\)。线段树维护最大、最小、\(a_i - b_j\)\(-b_j + a_k\)等标签,并进行合并操作。

CF1638E

采用颜色段均摊策略,合并时维护原\(sum\)与新颜色\(sum\)的差值。使用树状数组进行区间求和,最后进行单点查询并加上当前颜色的\(sum\)

P6617

注意到如果\(w - a_i\)出现在前一个\(a_i\)之前,则无意义,直接设置为0。因此只需维护少数关键点:当前点、原点的后一个相同点、原点的后一个\(w - a_i\)点、新点的后一个相同点、新点的后一个\(w - a_i\)点。

HDU7436 & CF813F

采用线段树分治,在区间上维护整个时间段都存在的边,然后在线段树上进行DFS。使用可撤销并查集维护连通性,当\(l=r\)时,给find(1)打上标记。在merge和roll-back操作时,使用类似前几题的差值方法维护被合并节点的\(time\)

T-shirt问题

考虑每个产品能被多少顾客购买。通过对产品排序,从小到大扫描,快速计算有多少顾客能买得起\(c_i\)。使用平衡树,暴力split出\(≥c_i\)的位置并直接相加。通过势能分析,平衡树维护相对顺序,只有区间\([c_i, 2×c_i - 1]\)内的顾客会改变相对顺序。修改一次会使原数减半,因此删除一个数最多需要\(log(c_i)\)次操作,总修改次数为\(n log(V)\)

Day5 数据结构3

CF459D

维护类似逆序对的结构即可。

CF1849E

采用扫描线策略,扫描r并计算\(f(l,r)\)表示\(l\)\(r\)是否满足条件,以及如何转移到\(f(l,r+1)\)。分类讨论发现,仅当\(a_{r+1}\)是最大值或最小值时才有影响。使用单调栈维护前缀最大和最小值,在线段树上直接修改每个l对应的\(f(l,r)\)

CF526F

等价于区间连续段问题,即区间内连续满足\(max - min = r - l\)。维护\(f(l,r) = max - min - (r - l)\),对每一项单独维护,最终查询\(f(l,r)=0\)的个数。转化为图论问题,对相邻数连边,令\(f(l,r)\)为点减边。每更新一个\(r+1\),点加一,相邻边加一。

Day6 字符串

CF176B

如果\(t\)能还原成\(s\),则可以通过一次操作完成。因此,所有不等于s但能变成s的字符串是等价的。于是有\(dp_{i,0/1}\)表示操作i步后是否是原串的个数。转移方程为:\(dp_{i,0} = dp_{i-1,1},dp_{i,1} = dp_{i-1,0} × (n-1) + dp_{i-1,1} × (n-2)\)

P4824

直接使用字符串哈希。

CF1721E

KMP自动机模板题,维护\(aut\)表示在第\(i\)个字符后添加字符\(c\)会跳转到的位置。

CF898F

注意加数和和的长度差不超过1。基数\(base\)为10,直接使用字符串哈希求解,可采用双模数或随机模数。

P8131

首先使用\(Manacher\)算法求出以每个点为中心的最长回文串长度。采用贪心策略,尽可能删除左边和右边的字符,最终得到一段连续字符串作为答案。模拟验证正确性。

P4696

问题与KMP相似,转化为判断子区间是否相同。由于是排列,比\(x\)大的数等于比\(y\)大的数,比\(x\)小的数等于比\(y\)小的数。使用树状数组维护,进一步地,只需x的前驱和y的前驱位置相同,\(x\)的后继和\(y\)的后继位置相同,则\(x\)\(y\)匹配。每个\(y\)的限制位置与\(a\)数组中\(x\)的限制位置相同,因此\(x\)\(y\)匹配。

Day7 动态规划1

CF1849D

直接贪心求解。连续1段中包含2时可以照顾两边的0,否则只能照顾一边。模拟求出未被覆盖的0的数量,加上连续段的数量。

CF1077F2

直接使用单调队列优化动态规划,注意转移过程。

CF1874C

概率动态规划问题。从下往上考虑图上的DP,节点u的DP值由子节点v的DP值决定。有\(dp_u = ∑ dp_v × P_{u,v}\),其中\(P_{u,v}\)是从\(u\)走到\(v\)的概率。\(P_{u,v}\)\(u\)无关,只与子节点数量和\(dp_v\)的排名有关。每次Jellyfish选择\(dp_v\)最大的子节点,因此\(P_{u,v}\)的递推较简单。更改状态为\(f_{i,j}\)表示子树大小为\(i\),当前排名第j位的概率。当\(j=1\)时,\(f_{i,j} = 1/i\);否则,考虑另一条边被删除的情况,设其排名为\(k\),如果\(1<k<j\),则j变为剩下的\(j-2\)排名,概率为\(f_{i-2,j-2} × (j-2)/i\);如果\(j<k\),则j变为\(j-1\)排名,概率为\(f_{i-2,j-1} × (i-j)/i\)。综合得到转移方程:\(f_{i,j} = f_{i-2,j-1} × (i-j)/i + f_{i-2,j-2} × (j-2)/i\)。然后进行DP转移,通过DFS求解。

Day9 动态规划2

CodeForces - 1324E

简单的动态规划,设\(f_{i,j}\)表示第\(i\)次睡觉在时间j时的良好睡眠次数最大值。注意初始化memset为负无穷。

CodeForces - 2000F

简单动态规划,设\(f_{i,j}\)表示到第\(i\)个任务获得\(j\)分所需的最少操作次数,\(f_{i,j} = min(f_{i-1,j-k} + g_{i,k})\),其中\(g_{i,k}\)可预处理。

CodeForces - 1557D

有效区间不超过\(2×m\)个,为每个区间编号。设\(f_i\)表示到第i个区间时最多能保留的区间数,\(f_i = max{f_j} + 1\),要求区间j与i重合。使用线段树维护区间上的f值最大值,同时维护pre记录当前区间最大值下标,使用pair<int, int>进行max转移。

CodeForces - 780F

构建的道路长度为\(2^i\)。设\(f_{p,l,r,0/1}\)表示是否存在长度为\(2^p\)的路径从\(l\)\(r\)的正/反路径。转移通过拼接长度为\(2^{p-1}\)的路径完成:\(f_{p,l,r,0} = f_{p-1,l,mid,0} \And f_{p-1,mid,r,1}\)。使用bitset维护f值,优化转移。

QOJ - 9879

数据范围不大,考虑乱搞。从\(i\)走到\(i+1\)的方式是先走到\((min(x_i, x_{i+1}), min(y_i, y_{i+1}))\),然后向两边走。合并两组点形成树结构,使用区间动态规划,设\(f_{l,r}\)为合并l到r的最小代价。合并后整个区间可视为\((min({x_i}), min({y_i}))\)继续合并,预处理区间最小值。

CodeForces - 771D

将交换操作次数分配到字符上。相同字符不交换,因此相对顺序不变。贡献转化为新串T中第i个字符c与原串中第\(i\)个字符c之前的其他字符出现次数的差值。暴力动态规划,设\(f_{i,j,k,0/1}\)表示前\(i+j+k\)个字符中,有\(i\)个'v',\(j\)个'K',\(k\)个其他字符,当前字符是否为'v'的最小交换次数。预处理第i个字符c前的其他字符数量,实现\(O(1)\)转移。

CodeForces - 1601D

贪心题。按\(max(s_i, a_i)\)排序。分类讨论:\(s_i > a_i\)时,可取\(s_i\)\(s_i < a_i\)时,如果\(s_i ≥ d\)则取,否则不取。策略是能取就取。

CodeForces - 311B

在直角坐标系上分析,每个饲养员管理结束时间减距离在一个区间内的猫。将结束时间减距离排序后,每个饲养员管理一个区间的猫。设\(f_{i,j}\)表示前i只猫用j个饲养员的最少等待时间,转移方程为\(f_{i,j} = min(f_{k,j-1} + cost_{k+1,i})\),其中\(cost_{l,r} = a_r × (r-l+1) - s_r + s_{l-1}\)。j的范围很小,可滚动数组优化。形式可斜率优化,\(y = f_{k,j-1} + s_k\)\(k = a_i\)\(x = k\)\(b = f_{i,j} - a_i × i + s_i\)。使用单调队列维护下凸包。

Day10 动态规划3

CodeForces - 1096D

水题,直接动态规划。设状态表示前i个字符不含"h"、"ha"、"har"、"hard"的最小操作次数。

P10156

分组求解。求一组内选j个人学OI的最小不满意度。设\(g_{i,j,0/1}\)表示前i个人选j个人,最后一个人没选的是否有伙伴的最小值。贡献绝对值拆开为\(a_i + x×i + a_j - x×j\),转移明显。最后简单DP汇总各组结果。

CodeForces - 1336C

从左或右添加字符通常使用区间动态规划。设\(f_{i,j}\)表示t中i到j字符有多少种合成方式。转移时,如果\(t_{i-1} = s_{i-j+2}\),则区间可向左拓展,\(f_{i-1,j} += f_{i,j}\);向右同理。在t后添加通配符'*',与任何字母配对。注意单个字符时可向前或向后插入,即\(f_{i,i} = 2\)

Gym - 104128B

如果没有修改,直接单调队列优化动态规划。修改影响[p, n+1]的值,暴力更新复杂度\(O(n^2)\)。注意到修改不影响从i(i>p)到n的价值,且修改长度很小,因此记录从i到n+1的价值,对修改区间暴力更新。最终答案为\(min_{i=p}{f_i + g_i - a_i}\)(a_i在f_i和g_i中重复计算)。细节较多。

代码实现略。

CodeForces - 1242C

首先判断是否合法,总和模k不等于0则不合法。每个数需要交换到特定数,连边后形成环则表示这些点可通过交换变得合法。答案由若干环拼成,环经过的箱子不重复。使用动态规划,\(f_i\)表示能否取i中为1的箱子,转移枚举子集,\(f_i = f_{i⊕s} AND vis_s\),其中\(vis_s\)表示是否存在s这些箱子的交换方式。记录转移来源以输出路径。

找环时维护环经过的箱子和环的行走方式,具体维护每个点的上一个点和当前点是哪个箱子的第几个数。

代码实现略。

Day11 组合数学1

CodeForces-1436C

模拟二分过程,判断哪些位置必须大于x,哪些位置必须小于等于x,然后排列组合计算。

P9306

如果将最大值放在第一位,答案较小。分类讨论:如果存在\((n,n)\)对,则答案为2,总方案为\((n-1)!\);否则答案为3,那么n一定在后面。

CodeForces-1696E

第(i,j)格的贡献为\(C(i+j, j)\)。一行的贡献为\(∑_{j=0}^{a_i} C(i+j, j) = C(i+a_i+1, a_i)\)。然后\(O(n)\)求和。

CodeForces-571A

正难则反,计算总数减去不合法方案。总数为\(∑_{i=0}^l C(i+2, 2)\)。不合法方案枚举最大边a,要求\(a ≥ b + c\),设a添加了l',则b+c部分添加了\(delta = min(l-l', a+l' - b - c)\)。答案为\(∑_{i=0}^{delta} C(i+1, 1) = ∑_{i=0}^{delta} i\),等差数列求和。

CodeForces - 1929F

将二叉搜索树转化为序列,得到一堆-1和正常数的序列,要求构造单调递增序列。考虑两个最近的非-1数a_i和a_j,中间有j-i个空格,将a_j - a_i分成j-i个非负部分插入,使用插板法解决。

CodeForces - 1227F2

先解决F1。设\(f_{i,j}\)表示做i题多对j题的方案数,有\(f_{i,j} = f_{i,-j}\),因此严格变大方案数为\((sum - f_{i,0})/2\),sum总方案数为\(k^n\)。求\(f_{n,0}\),考虑有i题从错变对,i题从对变错,其余不变。对变对时,只有\(a_i = a_{i+1}\)的情况,每种填对应数;错变错时,\(a_i = a_{i+1}\)有k-1种可能,否则有k-2种可能。因此,\(a_i = a_{i+1}\)时方案数为\(k^m\),否则枚举i,\(C(n-m, i)\)选择0→1的位置,\(C(n-m-i, i)\)选择1→0的位置,乘以\((k-2)^{n-m-2i}\)

P7118

点数比原树小时可全选,使用Catalan数,\(f_i = C(2i, i) - C(2i, i-1)\)。计算点数相同时的方案数,DFS处理,记\(dp_i\)为以点i为根的子树中大小相等的小于当前树的个数。对于子树,如果左子树大小小于原树的对应子树大小,直接用Catalan数\(dp_i = ∑_{i=0}^{sz_l} f_i × f_{sz_i - i - 1}\);左子树大小相等时,\(dp_i = dp_l × f_{sz_r}\);右子树相等时,\(dp_i = dp_r\)。三者相加。枚举时启发式处理,每次枚举左右子树中较小的sz,复杂度\(O(n log n)\)

CodeForces - 1237F

放横和竖不相关。设放i个竖和j个横,方案数相乘。求放i个竖的方案数,设\(dp_{i,j}\)表示前i个格子放j个的方案数,不放则\(dp_{i,j} = dp_{i-1,j}\),放则要求当前行和前一行为空,\(dp_{i,j} = dp_{i-2,j-1}\)。最终答案枚举放i个竖和j个横,总方案数为\(∑_{i=0}^{h/2} ∑_{j=0}^{w/2} C(ew - 2j, i) × f_{h,i} × C(eh - 2i, j) × g_{w,j}\),其中ew为空列数,eh为空行数。

Day13 组合数学2

CodeForces - 1795D

非常简单。

CodeForces - 1207D

需要容斥。\(a_i\)相同的可任意排序,\(b_i\)同理。但\(a_i = b_i\)的区间需减去这部分贡献以避免重复计数。

C - Sum of Goodness

计算每一位的贡献。有\(a_{i-1}\)个数比a_i小,因此选\(C(i-1, a_{i-1})\),后面的数随便选,乘以\(2^{n-i}\)。限制每一位的贡献不会重复计数。

CodeForces - 1666F

更新中...

CodeForces - 1924D

括号序列左边全是右括号,右边全是左括号;右括号数 = k - m,左括号数 = k - n;前缀和的最小值为右括号数。折线从(0,0)走到纵坐标\(m-k\),再走到\((n+m, n-m)\)。将(0,0)关于直线\(y=k-m\)\(y=k-m-1\)对称,求这两点到终点的方案数相减。新起点为\(2k-2m\),走\(n+m\)步到\(n-m\),需要\(x\)个+1,解出\(x=k\),方案数为\(C(n+m, k) - C(n+m, k-1)\)。需判断合法性。

Day14 图论1

CodeForces - 1255C

简单模拟。

P9650

Dijkstra的应用条件。从终点反推回起点,每个点阻拦到出口前\(d_i\)小的边。在反图上,删掉到i点的前\(d_i\)短路。实现时,将所有点入队,出队时判断是否前\(d_i\)短路,否则标记为已访问。

P5839

使用Floyd处理每个字符修改成另一个字符的操作数。然后动态规划,设\(f_i\)表示i之前的数合法的最小操作数,\(f_i = min(f_j + cost(j+1, i))\)\(cost\)表示将\([j+1, i\)]变为相同的最小操作数。预处理前缀和、前缀最小值,复杂度\(O(nm)\)

Gym - 104857J

枚举满足要求的边。边作为最大边产生贡献时,要求\(1→u\)\(v→n\)路径上的边权最大值小于等于该边权。因此求1→u路径上的最大值的最小值,使用Dijkstra从1和n各跑一遍。

P2934

最短路树与并查集缩点。最短路树是1到i的最短路径构成的树,断开最后一条边为\((fa_i, i)\)。用树外边更新答案,对于边\((u,v)\),能更新\(u\)\(v\)到根路径上的边,即对\([u, lca(u,v))\)\([v, lca(u,v))\)的边做贡献。贡献为\(dis_u + dis_v + w - dis_i\)。前三项确定,最后一项与节点有关。将边按值排序,枚举时用并查集缩点,更新一次后合并区间到lca(u,v),跳父亲时跳到find(fa),暴力更新复杂度\(O(m log n)\)

P6651

拓扑排序时求每个点对出度为0的点的链贡献数。从\(k=1\)开始,减去点u对答案的贡献,但u会下放到子节点,导致重复贡献。重复次数为出度为0的点到u的方案数,建反图可得。需要容斥,如果u能到v,则\(f_u\)会贡献到\(f_v\),重复\(f_u × d_{u,v}\)(u→v的方案数)。因此令\(f_v -= f_u × d_{u,v}\),总答案减去\(f_u × cnt_u\)

CodeForces - 875C

确定序列顺序需保证相邻两个递增。使用2-SAT。如果存在一位j使\(a_{i,j} < a_{i+1,j}\),则大小写相同,连边\(u→v \And v'→u'\);如果\(a_{i,j} > a_{i+1,j}\),则u大写v小写,连边\(u→u' \And v'→v\);如果a_{i+1}是a_i的前缀,则不可能。连边后跑2-SAT,判断拓扑序决定大小写。

P6062

类似最大权闭合子图。树上的点放在源点侧,连点权;限制条件放在汇点侧,连容量\(c_i\)。每个点与对应的限制条件连无穷容量。最大流为\(∑a_i - max_{flow}\),50分。放在树上,源点连节点,有限制条件的点连汇点。源点流向\(x_i\)子树下距离\(≤k_i\)的点再流向汇点。用map统计每个深度的总容量,启发式合并。处理限制条件时,二分深度\(≤dep_u + k_u\)且有剩余容量的深度,暴力更新减去\(c_i\)。复杂度\(O(n log n)\)

Day15 图论2

CodeForces - 1679D

二分答案,重新建图后跑拓扑排序。如果有环则无限走,合法;否则为DAG,求最长路径。

CodeForces - 1213F

强连通分量缩点。同一连通分量内字母相同。缩点后的DAG,拓扑序\(≤k\)的填对应字母,否则填'z'。

CodeForces - 2000G

反着做,求从\(u\)出发到\(n\)的最晚出发时间。使用Dijkstra求最大值。到达点时需要打电话,可能走路或等待后坐车。用最晚到达时间更新,Dijkstra板子。

P2416

边双连通分量。边双内任意两点有两条不重合路径,因此边双内有贡献的边都能取到。缩点后构成树,u→v路径唯一。路径和为\(s_u + s_v - 2 × s_{lca(u,v)} + a_{lca(u,v)}\),a为点权。

P11907

三维转序列操作。点连边到上下左右前后六个方向,处理每个点到餐厅的距离。点权转边权,边权为连接两点的dis最小值。最大生成树上u→v的边权最大值,即Kruskal重构树的\(val_{lca(u,v)}\)

vector使用技巧:vector<vector<vector>> a; 每维resize()。

Day17 树上问题1

CodeForces-1336A

贪心选叶子节点,再选子节点数小的点。点\(u\)建工业城市的贡献为\(dep_u - 1 - cnt_u\)\(cnt_u\)为子树u的工业城市数,即\(sz_u - 1\)。排序选前\(k\)大。

P5536

贪心,要求点到叶子节点距离最小值最大,即树的重心(直径中点)。确定点后BFS取前k个点,计算距离。或从叶子节点BFS直到剩k个节点,计算距离。

CodeForces-771C

树形DP。设\(f_{u,i}\)表示到\(u\)节点还剩\(i\)步的总步数。合并\(u\)\(v\)时分类讨论:如果\(k-i≤j\)\(k-j≤i\),则方案数为\(f_{u,i}×cnt_{v,j} + f_{v,j}×cnt_{u,i} - cnt_{u,i}×cnt_{v,j}\);否则为\(f_{u,i}×cnt_{v,j} + f_{v,j}×cnt_{u,i}\)。转移\(f_{u,i} += f_{v,i+1},cnt_{u,i} += cnt_{v,i+1}\)。注意\(i=k-1\)时,\(i+1=k\),需加\(cnt_{v,i+1}\)\(cnt\)不变。最后加上从$u出发的点对。

CodeForces - 2033G

答案為u向上走\(≤k\)步後向下走的最大距离。倍增维护,\(f_{u,i}\)表示從\(u\)向上\(2^i\)步的最大距离。\(f_{u,i} = max(f_{fa_{u,i-1}, i-1} + 2^{i-1}, f_{u,i-1})\)。查詢時向上跳,于\(min(dep_u-1, k)\)\(max\)

CodeForces - 1709E

我们可以将每个顶点视为 LCA 进行处理。若发现两个顶点不合法,则需替换其中一个节点。最优策略是将 LCA 替换为一个极大的数值,从而避免其子节点向上贡献。随后,对于每个节点维护一个 set,存储所有到 LCA 的路径异或和。若发现两棵不同子树中存在异或和等于当前 LCA 值的情况,则需要进行修改;否则,合并这些 set。采用启发式合并,时间复杂度为 \(O(n \log^2 n)\)

CodeForces - 1794E

哈希 + 换根 DP

若要匹配序列,可采用哈希方法将整个序列压缩为一个哈希值,并通过比较哈希值判断是否匹配。建议使用双模数哈希以增强鲁棒性。哈希值可定义为 \(\text{Base}^{\text{dep}_u}\),直接比较即可。状态转移也较为直观。若序列中缺失某个数值,则考虑随机填充该位置的影响,其贡献为 \(\text{Base}^x\)。只需检查目标值与当前哈希值的差是否为 \(\text{Base}\) 的幂次。

DAY18 树上问题 2

洛谷 - P8578

直接填充 DFS 序即可。

CodeForces - 1244D

由于每个节点度数最多为 2,可暴力枚举链末端两个节点的颜色,并验证整个路径的代价。

CodeForces - 1790F

每次添加新节点时,其与最近黑点的距离不会太大。直接 BFS 可能超时,因此转为维护每个点到最近黑点的距离。当染色到 \(u\) 时,设其距离为 \(\text{dis}_u\),然后 BFS 更新邻近节点,但需剪枝:若当前距离超过已知答案则停止。证明复杂度:初始时 BFS 最多运行 \(n\) 步,添加 \(x\) 个点后总步数为 \(O(nx)\),但实际运行中每点平均更新次数为常数,因此可通过。

Gym - 102012G

点-边容斥

直接对点计算组合数 \(C(\text{cnt}, k)\) 会重复计数,因为路径可能共享边。利用子树中点数减边数恒为 1 的性质,采用点减边方法:点的贡献减去边的贡献。对每条路径进行树上差分,分别处理点和边,最后自底向上前缀和统计答案。

DAY 19 数论

CodeForces-947A

线性筛

由关系式 \(\lceil \frac{X_1}{b} \rceil \times b = X_2\)(其中 \(b \mid X_2\))可得,对于每个质因数 \(b\)\(X_1\) 的取值范围为 \([X_2 - b + 1, X_2]\)。同理,\(X_0\) 的取值范围为 \([X_1 - a + 1, X_1]\)\(a \mid X_1\))。贪心策略是使 \(X_1\) 尽可能小且 \(a\) 尽可能大。预处理每个数的最大质因数,枚举 \(X_1\) 并记录 \(X_0\) 的最小值。

CodeForces-1499D

\(a = k_1 \cdot \gcd(a,b)\), \(b = k_2 \cdot \gcd(a,b)\),则 \(\text{lcm}(a,b) = \frac{a b}{\gcd(a,b)}\)。原式化为 \(k_1 k_2 c \cdot \gcd(a,b) - d \cdot \gcd(a,b) = x\),解得 \(\gcd(a,b) = \frac{x}{k_1 k_2 c - d}\)。枚举 \(\gcd(a,b)\)(为 \(x\) 的因数),计算对应的 \((k_1, k_2)\) 数量。由于 \(\gcd(k_1, k_2) = 1\),每种质因数只能出现在 \(k_1\)\(k_2\) 中,故方案数为 \(2^p\)\(p\) 为质因数种数)。预处理每个数的质因数个数,复杂度为 \(O(T \cdot \sqrt{x})\)

洛谷-P12021

限制条件形成若干不交链。链的贡献用动态规划计算:\(f_i\) 表示长度为 \(i\) 的链的方案数,转移为 \(f_i = f_{i-1} + f_{i-2}\)(取或不取当前点)。链的条数通过容斥计算:先求长度至少为 \(l\) 的链的数量,再减去长度至少为 \(l+1\) 的数量。通过数轴分析,从 \(n/k\)\(n\) 的点无需跳跃,而从 \(1\)\(n/k\) 的点需跳跃一次。分段计算方案数,总方案数减去前缀方案数即为当前段方案数。

代码实现见原题解。

洛谷-P12952

转化为线性同余方程 \(ax \equiv b \pmod{n}\)

线性同余方程

结论:方程 \(ax \equiv b \pmod{n}\) 等价于 \(ax + kn = b\)。通过扩展欧几里得算法求解 \(x_0, k_0\) 满足 \(x_0 a + k_0 n = \gcd(a,n)\),则原方程的特解为 \(x = x_0 \cdot \frac{b}{\gcd(a,n)}\)。若 \(\gcd(a,n)=1\),则通解为 \(x = x_0 + n t\), \(k = k_0 - a t\)\(t\) 为任意整数)。最小非负整数解为 \(x = (x \bmod t + t) \bmod t\),其中 \(t = \frac{n}{\gcd(a,n)}\)。欲最小化 \(|x|\),可先求最小非负解 \(x_1\),再取 \(-(x_1 - t)\)

P6583 回首过去

整除分块

分数可化为有限小数的条件是分母仅含质因子 2 或 5。将分数写为 \(\frac{b c}{a c}\),其中 \(\frac{b}{a}\) 已约分,且 \(c\) 不含 2 或 5 的因子。枚举 \(a\),则 \(c\) 的取值范围为 \(1\)\(\lfloor \frac{n}{a} \rfloor\)\(b\) 的取值范围为 \(1\)\(\lfloor \frac{n}{c} \rfloor\)。直接枚举复杂度为 \(O(n^2)\),改为枚举 \(c\),则 \(a\) 的取值范围单调,答案可写为 \(\sum_c \lfloor \frac{n}{c} \rfloor \cdot f(\lfloor \frac{n}{c} \rfloor)\),其中 \(f(x)\) 表示不超过 \(x\) 且不含 2 或 5 因子的数的个数。整除分块后容斥计算 \(f(x)\),总复杂度为 \(O(\sqrt{n} \log n)\)

posted @ 2025-09-05 22:35  2020luke  阅读(32)  评论(0)    收藏  举报