日志
2025.5.19
Asm.Def的基本算法 2.5* 组合数学加dfs
天天爱射击 3.5* 想了2h的主席树被log^2卡了,看题解整体二分过的
赛道修建 3* lca+二分
UNO 3.5* 沟槽的组合数学调了一整个晚自习
总计12.5*
2025.5.20

共计15.5*
2025.5.23
最小公倍数 3.5* 连通图分块+并查集
模积和 3.5* 之前遗漏的整除分块板子
蔬菜 3.5* 贪心,注意倒推
起床苦难综合征 2.5* 简单的位运算
2025.5.26
ARC198
A.因为每一个 k≥2 都有 (k+1)modk=1 ,所以两个连续的整数不可能都属于
S 。满足[s]=[k/2]递推,O(n)求出
B.分类讨论,x为一般时首先,写出 X 个零。然后,在 Z 个零之间的空隙中插入 2。如果 Y 是奇数(那么就是 Z≥1 ),选取一个片段 (0,2,0),插入一个 1 将其转化为 (0,1,2,0),使得 Y 成为偶数。然后,进行以下操作2y次(0,0)→(0,1,1,0),(0,2,0)→(0,1,2,1,0)
D.BFS预处理每个节点对(i,j)的路径长度和路径中的第一个邻接节点,优先队列按路径长度降序处理所有满足A[i][j]=1的节点对,合并这些节点,dp按路径长度升序处理所有节点对,判断其父节点对是否回文,并统计回文对数目
2025.5.27
最大异或和路径 线性基
Florr dfs
[ABC290F] Maximum Diameter 组合数学 范德蒙德卷积,用完了才知道这个名字
[ARC156C] Tree and LCS 用队列完成构造,思维题
2025.5.28
P5749 [IOI 2019] 排列鞋子
运用贪心算法,从后往前推,找到最近的可匹配就移过来更新答案,用vector存储位置,那么我们每一个尺码匹配的vector的最后一个一定是最近的,用树状数组维护答案
AT_abc285_e [ABC285E] Work or Rest
定义数列 (S_i),表示一周有 (i+1) 天(即 (i) 个工作日)且只有 1 个休息日时的工作效率:
- 若 (i) 为奇数,(S_i = 2 \sum_{j=1}^{\lfloor i/2 \rfloor} A_j + A_{\lceil i/2 \rceil})
- 若 (i) 为偶数,(S_i = 2 \sum_{j=1}^{i/2} A_j)
定义 (F_i) 为一周有 (i) 天时的最大工作效率,计算方式为:
固定第一个休息日为周一,枚举第二个休息日位置,将周划分为两部分,则 (F_i = \max_{k=2}^{i-2} (F_k + F_{i-k}))
取两者较大值:(F_i = \max(S_{i-1}, \max_{k=2}^{i-2} (F_k + F_{i-k})))。
最终答案即 (F_N)。边界如 (i=1, 2, 3) 时仅考虑单休息日
国家集训队] 等差子序列
举每个位置作为中间项,检查是否存在一个数对分别位于中间项的左右两侧。利用动态维护的01序列,把左边的设为1,右边的设为0,通过线段树快速判断以中间项为中心的对称区间是否回文,每个节点存储区间长度、正向和反向哈希值,运用哈希值判断是否回文,若区间非回文,则存在有效数对,计数加1
然后注意维护的时候中间项不能是序列尾首
6.10
P2371 [国家集训队] 墨墨的等式
找出所有面值中最小的那个,记为m。所有金额k都可以表示为k = tm + j,其中j是k除以m的余数(0 ≤ j < m)。
对于每个余数j,存在一个最小的t_j,使得当t ≥ t_j时,tm + j都能被组合出来。把0到m-1的余数作为图中的节点。对于每个余数u和每种面值aᵢ,计算新余数v = (u + aᵢ) % m,边权为⌊(u + aᵢ)/m⌋(表示跨越了多少个m)。从0出发(因为金额0总是可以组合),用Dijkstra算法求出到每个余数j的最短路径t_j。
对于每个余数j:
最小可组合金额是base_j = t_j * m + j
P2565 [SCOI2009] 骰子的学问
在[L,R]区间内,满足k ≡ j (mod m)且k ≥ base_j的k的个数就是答案贡献
首先,我们把骰子之间的"大于"关系看作有向边,这样会形成一个基环内向树森林(每个点出度为1的有向图)。
处理非环部分(树状结构)
对于不在环上的骰子,我们可以采用贪心策略:
让父骰子的所有面都比子骰子的最大面大
这样直接从大到小填数即可
处理环部分
这才是本题的难点。对于环上的q个骰子,我们需要用q×m个数构造一个满足条件的环。
核心构造方法是:
选择一个骰子,沿父方向依次填(1,2,...,m)
选择下一个骰子,沿父方向填(m+1,...,2m)
重复直到填满
这种构造能保证相邻骰子满足概率条件。不过有个特殊情况需要特判:当环大小为3且骰子面数为4时,需要采用题目给出的样例填法。
P2566 [SCOI2009] 围豆豆
状态压缩!!!!
DP肯定要开数组存结果。这题二维数组不够用,因为既要记录坐标又要记录状态。
设f[x][y][s]表示走到点(x,y)且状态为s时的路径长度。状态s用9位二进制数表示(最多9个豆豆),比如:
0000表示没围住任何豆豆
0010表示围住了第2个豆豆
0111表示围住了前3个豆豆
注意每次换起点都要重新初始化f数组。
如何判断围住豆豆
豆豆被围住的条件:从豆豆向右引射线,如果与路径的交点是奇数个则被围住(射线定理)。但要注意:
只有上下移动才计数,水平移动不算
路径必须在豆豆右侧
for(int i=1;i<=d;i++){
if(((mxax[i] && nx<ax[i]) || (mx<ax[i] && nxax[i])) && ny>ay[i]){
ns^=(1<<(i-1));
}
}
转移方程式
for(int i=0;i<mmax;i++){
for(int j=1;j<=d;j++){
if(i&(1<<(j-1))) val[i]+=da[j];
}
}
6.11
CF53E Dead Ends
这道题的标准解法是状态压缩DP
我们定义状态f[S1][S2]:
S1:已与节点1联通的节点集合S2:当前度数为1的节点集合
转移过程:每次选择一条边(u,v),其中u在S1中而v不在,将v加入S1和S2,如果u原本在S2中就移除它。
直接这样做会导致重复计数,比如样例1中:
- 路径
(1,2)(1,3)会被计算两次 - 路径
(1,3)(1,2)又会被计算两次
-
唯一生成路径:对于任何生成树,存在唯一的加边顺序——按照叶子节点编号从大到小依次加入。
-
排除非法顺序:如果尝试以其他顺序加入节点,在加入较小编号节点时,会检测到存在更大编号的叶子节点,从而阻止转移。
UVA1205 Color a Tree
贪心,树中除根节点外权值最大的点,一定会在它的父节点被染色后立即染色
考虑三个节点a,b,c,其中a和b是父子关系且需要连续染色:
两种染色顺序:
- 先染a,b,再染c:代价 = a + 2b + 3c
- 先染c,再染a,b:代价 = c + 2a + 3b
比较两种顺序的代价差:
(a + 2b + 3c) - (c + 2a + 3b) = 2c - a - b
因此,当2c > a + b(即c > (a+b)/2)时,第一种顺序更优。这正好验证了我们应该按照平均值来决定合并顺序。
CF387D George and Interesting Graph
由于数据范围小,我们可以暴力枚举每个节点作为中心点的情况。
对于每个候选中心点i:
into[i]:指向i的边数out[i]:从i指出的边数- 需要的操作数:
2n-1 - into[i] - out[i](因为理想中心点应该有n-1条入边和n-1条出边,加上自环)
剩下的节点需要形成环,这可以转化为二分图匹配问题: - 左部:所有非中心节点作为起点
- 右部:所有非中心节点作为终点
- 边:原始图中存在的边(不包括与中心点相关的边)
ans = (2n-1 - into[i] - out[i]) + (m - into[i] - out[i] - p) + (n-1 - p)
6.12
CF1776I Spinach Pizza
每次选择当前多边形中面积最小的三角形对应的顶点进行删除,这样可以保证:
- 三角形面积序列是非递减的
- 先手可以控制游戏进程
设当前最小三角形是ABC,其中B是被删除的顶点:
- 删除B后形成边AC
- 任何包含AC的新三角形面积都不会超过ABC
- 因为根据引理,其他以AC为底的三角形面积更大
- 这样保证了三角形面积序列的非递减性
CF1120D Power Tree
- 首先对树进行DFS遍历,为每个叶节点分配连续的DFS序
- 对于每个非叶节点u,其控制范围是子树中所有叶节点的DFS序区间
[dfnl[u], dfnr[u]] - 将区间加减操作转化为差分数组上的单点修改
- 控制区间
[l,r]等价于在差分数组上执行c[l]+x和c[r+1]-x - 最终目标是让所有
c[1..n]变为0,这意味着所有修改量最终都转移到c[n+1] - 将每个控制区间
[l,r]看作一条从l到r+1的边,边权为控制该节点的代价 - 问题转化为:选择一些边使得节点
n+1与所有其他节点连通,且总代价最小 - 这正好是最小生成树问题
CF414C Mashmokh and Reverse Operation
预处理阶段
- 使用类似归并排序的方法,递归地将序列分成两半
- 在合并过程中,统计每一层的顺序对(cnt[x][1])和逆序对(cnt[x][0])
- 保存排序后的子序列用于后续处理
查询处理
- 对于每个查询q,影响所有层次≤q的分块
- 交换这些层次的顺序对和逆序对计数
- 将所有层次的逆序对求和得到总逆序对数
6.13
CF765F Souvenirs
- 离线处理:将所有查询按照右端点排序
- 权值线段树:维护值域信息,快速找到满足条件的元素
- 差值减半优化:利用数学性质减少需要考虑的元素数量
- 树状数组:维护后缀最小值
- 差值减半:每次查找时,只考虑能使差值至少减半的元素,将复杂度从O(n)降到O(logV)
- 两次处理:第一次处理
a[j] > a[i]的情况,第二次将数组翻转处理a[j] < a[i]的情况
CF1422F Boring Queries
- 质因数分解:将每个数分解质因数
- 逆元处理:使用逆元来消除重复质因数的影响
- 主席树:维护历史版本,支持区间查询
- 质因数分解预处理:使用筛法预处理最小质因数
- 动态维护质数幂次:记录每个质数幂最后出现的位置
- 主席树合并:通过合并操作维护区间乘积
CF468C Hack it!
我们需要找到区间 [l, r] 使得:
∑(i=l to r) f(i) ≡ 0 (mod a)
其中 f(i) 表示数字 i 的各位数字之和。
-
数字和的性质:对于任意数字
x,有f(x + 10^18) = f(x) + 1 -
周期性模式:这个性质导致求和结果呈现周期性变化
-
设
p = ∑(i=0 to 10^18-1) f(i) mod a -
根据数字和的性质,可以推导出:
∑(i=1 to 10^18) f(i) ≡ p + 1 (mod a)∑(i=2 to 10^18+1) f(i) ≡ p + 2 (mod a)- ...
∑(i=a-p to 10^18+a-p-1) f(i) ≡ 0 (mod a)
-
计算
p的值:∑(i=0 to 10^18-1) f(i) = 81 × 10^18- 所以
p = 81 × 10^18 mod a
6.16
CF1758E Tick, Tock
对于没有-1的矩阵,合法条件是:对于任意两列,所有行在这两列的差值必须相同。
使用边带权并查集来维护列与列之间的关系:
-
对于每行非全-1的行,建立列之间的关系
-
检查是否存在矛盾(同一列在不同行被要求取不同值)
-
如果发现矛盾,则无解
-
统计连通块数量x(列之间的关系形成的连通分量)
-
统计全-1行数量y
-
方案数为:
- 非全-1行:h^(x-1)
- 全-1行:h^y
- 总方案数:h^(x+y-1)
CF1783F Double Sort II
对于单个排列,可以建模为有向图,其中i→a_i。此时:
- 每个环可以通过|环长|-1次操作解开
- 总操作次数 = n - 环数
对于两个排列,我们需要同时考虑两个图:
- 建立两个图:G_a(i→a_i)和G_b(i→b_i)
- 每个点在G_a和G_b中分别属于某个环
- 问题转化为:选择一些点不操作,使得:
- 每个环最多选一个点
- 选中的点在两个图中属于不同环
- 将G_a的环作为左部,G_b的环作为右部
- 对于每个点i,连接其所在的G_a环和G_b环
- 最大匹配即为最多可以不操作的点数
- 最小操作次数 = n - 最大匹配
CF1237E Balanced Binary Search Trees
先找一下规律
- 深度1:只能是单个节点(大小1)
- 深度2:只有一种结构(大小2)
- 深度3:可以构造大小4或5的树
看起来每个深度对应的树大小很有规律性。
深入分析后发现几个关键点:
- 右子树必须是偶数大小:因为树的最后一个节点(最右下角)必须和根节点同奇偶
- 递归结构:整棵树满足条件,那么它的左右子树也必须满足条件
- 大小限制:每个深度d,树的大小只能是f[d]或f[d]+1
通过归纳法可以证明:
- 如果深度d的树最小大小f[d]是偶数:
f[d+1] = 2*f[d] + 1 - 如果是奇数:
f[d+1] = 2*f[d] + 2
比如:
- f[1]=1(奇数)→ f[2]=2*1+2=4
- f[2]=4(偶数)→ f[3]=2*4+1=9
- f[3]=9(奇数)→ f[4]=2*9+2=20
直接找出递推式
f[d+1] = 2*f[d] + (1 if f[d]%2==0 else 2)
6.17
[POI 2014] SUP-Supercomputer
问题描述
给定一棵树,每次操作可以选最多k个节点删除,但要求这些节点的父节点必须已经被删除。问最少需要多少次操作才能删完整棵树。
思路
最直接的思路就是分层删除:
- 先删第一层(根节点)
- 再删第二层(根的子节点)
- 依此类推...
但是这样效率可能不高,因为每次操作最多可以删k个节点,我们希望能尽量"填满"每次操作。
最优解其实满足一个很漂亮的性质: - 存在一个分界层x,前x层刚好用x步删完
- x层之后的节点每次都能删满k个(最后一次可能不足)
为什么这样最优?
- 前x层至少需要x步(每层至少一次)
- 后面每次都尽量删最多,次数自然最少
证明
假设我们已经用y步删了前x层(y≥x),后面可以每次删k个。那么一定存在更优的方案:
- 找最近的x'层,使得从x'到x层可以更高效地删除
- 通过调整,让x'层满足:
- 前x'层用x'步删完
- 后面每次都能删k个
- 这样操作次数更少
算法
-
预处理:
- 计算每层节点数
- 计算s[i](i层之后的节点总数)
-
最优解公式:
f(k) = max -
用斜率优化快速计算:
- 把问题转化为找凸包上的切点
- O(n)预处理,O(1)查询

浙公网安备 33010602011771号