日志

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时,t
    m + 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),其中uS1中而v不在,将v加入S1S2,如果u原本在S2中就移除它。
直接这样做会导致重复计数,比如样例1中:

  • 路径(1,2)(1,3)会被计算两次
  • 路径(1,3)(1,2)又会被计算两次
  1. 唯一生成路径:对于任何生成树,存在唯一的加边顺序——按照叶子节点编号从大到小依次加入。

  2. 排除非法顺序:如果尝试以其他顺序加入节点,在加入较小编号节点时,会检测到存在更大编号的叶子节点,从而阻止转移。

UVA1205 Color a Tree

贪心,树中除根节点外权值最大的点,一定会在它的父节点被染色后立即染色
考虑三个节点a,b,c,其中a和b是父子关系且需要连续染色:

两种染色顺序:

  1. 先染a,b,再染c:代价 = a + 2b + 3c
  2. 先染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

每次选择当前多边形中面积最小的三角形对应的顶点进行删除,这样可以保证:

  1. 三角形面积序列是非递减
  2. 先手可以控制游戏进程

设当前最小三角形是ABC,其中B是被删除的顶点:

  1. 删除B后形成边AC
  2. 任何包含AC的新三角形面积都不会超过ABC
    • 因为根据引理,其他以AC为底的三角形面积更大
  3. 这样保证了三角形面积序列的非递减性

CF1120D Power Tree

  • 首先对树进行DFS遍历,为每个叶节点分配连续的DFS序
  • 对于每个非叶节点u,其控制范围是子树中所有叶节点的DFS序区间[dfnl[u], dfnr[u]]
  • 将区间加减操作转化为差分数组上的单点修改
  • 控制区间[l,r]等价于在差分数组上执行c[l]+xc[r+1]-x
  • 最终目标是让所有c[1..n]变为0,这意味着所有修改量最终都转移到c[n+1]
  • 将每个控制区间[l,r]看作一条从lr+1的边,边权为控制该节点的代价
  • 问题转化为:选择一些边使得节点n+1与所有其他节点连通,且总代价最小
  • 这正好是最小生成树问题

CF414C Mashmokh and Reverse Operation

预处理阶段

  1. 使用类似归并排序的方法,递归地将序列分成两半
  2. 在合并过程中,统计每一层的顺序对(cnt[x][1])和逆序对(cnt[x][0])
  3. 保存排序后的子序列用于后续处理

查询处理

  1. 对于每个查询q,影响所有层次≤q的分块
  2. 交换这些层次的顺序对和逆序对计数
  3. 将所有层次的逆序对求和得到总逆序对数

6.13

CF765F Souvenirs

  1. 离线处理:将所有查询按照右端点排序
  2. 权值线段树:维护值域信息,快速找到满足条件的元素
  3. 差值减半优化:利用数学性质减少需要考虑的元素数量
  4. 树状数组:维护后缀最小值
  • 差值减半:每次查找时,只考虑能使差值至少减半的元素,将复杂度从O(n)降到O(logV)
  • 两次处理:第一次处理 a[j] > a[i] 的情况,第二次将数组翻转处理 a[j] < a[i] 的情况

CF1422F Boring Queries

  1. 质因数分解:将每个数分解质因数
  2. 逆元处理:使用逆元来消除重复质因数的影响
  3. 主席树:维护历史版本,支持区间查询
  • 质因数分解预处理:使用筛法预处理最小质因数
  • 动态维护质数幂次:记录每个质数幂最后出现的位置
  • 主席树合并:通过合并操作维护区间乘积

CF468C Hack it!

我们需要找到区间 [l, r] 使得:

∑(i=l to r) f(i) ≡ 0 (mod a)

其中 f(i) 表示数字 i 的各位数字之和。

  1. 数字和的性质:对于任意数字 x,有 f(x + 10^18) = f(x) + 1

  2. 周期性模式:这个性质导致求和结果呈现周期性变化

  3. p = ∑(i=0 to 10^18-1) f(i) mod a

  4. 根据数字和的性质,可以推导出:

    • ∑(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)
  5. 计算 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. 对于每行非全-1的行,建立列之间的关系

  2. 检查是否存在矛盾(同一列在不同行被要求取不同值)

  3. 如果发现矛盾,则无解

  4. 统计连通块数量x(列之间的关系形成的连通分量)

  5. 统计全-1行数量y

  6. 方案数为:

    • 非全-1行:h^(x-1)
    • 全-1行:h^y
    • 总方案数:h^(x+y-1)

CF1783F Double Sort II

对于单个排列,可以建模为有向图,其中i→a_i。此时:

  • 每个环可以通过|环长|-1次操作解开
  • 总操作次数 = n - 环数
    对于两个排列,我们需要同时考虑两个图:
  1. 建立两个图:G_a(i→a_i)和G_b(i→b_i)
  2. 每个点在G_a和G_b中分别属于某个环
  3. 问题转化为:选择一些点不操作,使得:
    • 每个环最多选一个点
    • 选中的点在两个图中属于不同环
  • 将G_a的环作为左部,G_b的环作为右部
  • 对于每个点i,连接其所在的G_a环和G_b环
  • 最大匹配即为最多可以不操作的点数
  • 最小操作次数 = n - 最大匹配

CF1237E Balanced Binary Search Trees

先找一下规律

  • 深度1:只能是单个节点(大小1)
  • 深度2:只有一种结构(大小2)
  • 深度3:可以构造大小4或5的树

看起来每个深度对应的树大小很有规律性。

深入分析后发现几个关键点:

  1. 右子树必须是偶数大小:因为树的最后一个节点(最右下角)必须和根节点同奇偶
  2. 递归结构:整棵树满足条件,那么它的左右子树也必须满足条件
  3. 大小限制:每个深度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个节点删除,但要求这些节点的父节点必须已经被删除。问最少需要多少次操作才能删完整棵树。

思路

最直接的思路就是分层删除:

  1. 先删第一层(根节点)
  2. 再删第二层(根的子节点)
  3. 依此类推...
    但是这样效率可能不高,因为每次操作最多可以删k个节点,我们希望能尽量"填满"每次操作。
    最优解其实满足一个很漂亮的性质:
  4. 存在一个分界层x,前x层刚好用x步删完
  5. x层之后的节点每次都能删满k个(最后一次可能不足)
    为什么这样最优?
  • 前x层至少需要x步(每层至少一次)
  • 后面每次都尽量删最多,次数自然最少

证明

假设我们已经用y步删了前x层(y≥x),后面可以每次删k个。那么一定存在更优的方案:

  1. 找最近的x'层,使得从x'到x层可以更高效地删除
  2. 通过调整,让x'层满足:
    • 前x'层用x'步删完
    • 后面每次都能删k个
  3. 这样操作次数更少

算法

  1. 预处理:

    • 计算每层节点数
    • 计算s[i](i层之后的节点总数)
  2. 最优解公式:
    f(k) = max

  3. 用斜率优化快速计算:

    • 把问题转化为找凸包上的切点
    • O(n)预处理,O(1)查询
posted @ 2025-05-19 21:27  健康铀  阅读(25)  评论(0)    收藏  举报