【test】日照集训 Day1

考试题解

A

一个序列,可以进行一次区间加 k 操作,其中 k 是固定值。求序列最大公因数最大是多少

题解

枚举,预处理出来前缀后缀 gcd 值,中间扫过去计算区间加 \(k\) 后的 gcd,然后合并
答案。

答案很小的时候:枚举答案!找每个位置需要/不需要被加 \(k\),需要加 \(k\) 的位置形成一个区间则该答案可行。时间复杂度 \(O(n \times v)\)

答案是由前缀 gcd,后缀 gcd,中间区间整体加 \(k\) 后的 gcd 拼起来的,前缀 gcd 只有 \(O(\log v)\)段,每一段一定是取最大的 \(l\) 最优,所以有用的 \(l\) 只有 \(O(\log v)\) 个固定一个左端点,暴力扩展右端点计算,单次 \(O(n)\),总时间复杂度 \(O(n\log v)\)

单次 时间复杂度证明:两个数相同时,gcd 复杂度 \(O(1)\);两个数不同时,gcd 复杂度 \(O(\log n)\)。最多只有 \(O(\log n)\) 个不同,时间复杂度 \(O(n + \log^2 n )\)

B

有向图边有边权。走边需要花钱,初始有 \(p\) 的钱,每在一个点工作一次赚 \(a_i\) 的钱,问从 \(1\)\(n\) 最少需要工作几次。\(n \le 800 ,m \le 3000\)

题解

如果 \(a_1\) 是最大值:所有工作都在 \(1\) 号点进行,最短路 计算答案。

如果图是一棵 外向树:只有 \(1\)\(n\) 的链有用!变成一个 序列问题。设 \(f_i\) 表示 \(1\) 走到了 \(i\) 号点最少工作次数,但是这个信息不够,还需要记录最少工作次数下现在最多的钱的数量。每次从 \(i\) 走到 \(i + 1\) 如果钱足够就直接走,如果钱不够,选择在序列前缀中最大的 \(a_i\) 的点工作,相当于是以前走到那个点的时候多工作一些次数现在把钱带过来(延迟工作)。时间复杂度 \((O(n + m)\)

状态答案记录二元组 (最少工作次数,最多钱数),这两维严格偏序,即先满足最少工作次数,再满足目前钱数最多。因为只有迫在眉睫需要钱再去工作,而走的越远,可能会遇到更大的 ,工作获得的收益会更大。

如果图是 DAG:设 \(f_i\) 仍如前文设计,则走到 \(i\) 点有很多条路径,不知道走过来的最大的 是哪一个。那就额外记录下来最大的 \(a_i\) 的位置,设 \(f_{i,x}\) 表示走到了 \(i\),一路走来最大 \(a_i\) 位置在 \(x\),现在的(最少工作次数,最多钱数)。这样转移。时间复杂度 \(O(n\times m)\)

对于一般图把这个东西上 dijstra 转移。时间复杂度 \(O(nm \log n)\)(对于一个 \(i\),最多 \(m\) 条边相连,所以最多 \(m\) 个最大值位置)。

C

题解

首先注意到性质:对于一个连通块,只保留次大值到最大值的链,这样一定是最优的(扔掉多余的点,可能还能造成额外贡献)。

因此考虑 dp。设 \(f_{u,i}\) 表示 \(u\) 子树内除了一条 \(u\) 点到权值为 \(i\) 的点的链没有贡献外,其余点都贡献了的 最优答案,设 \(g_u\) 表示 \(u\) 子树内的点都贡献的 最优答案

新加入一个儿子 \(v\) 时有转移:

  • \(g_u = \max(g_u + g_v, f_{u,i} + f_{v,j} + \min(i, j))\)
  • \(f_{u,i} = \max(f_{u,i} + g_v,\sum_{ch \ne v} g_{ch} + f_{v,i})\)

注意,这里 \(i\) 可以等于 \(w_u\)

每次暴力转移,单次 \(O(n^2)\),总时间复杂度 \(O(n^3)\)
发现瓶颈主要在于第一条转移。发现可以把 \(\min\) 拆开,于是

  • \(g_u = \max(g_u + g_v, f_{u,i} + i + f_{v,j})(i\le j)\)
  • \(g_u = \max(g_u + g_v, f_{u,i} + f_{v,j} + j)(i > j)\)

发现可以记录前缀 \(pre_i\) 表示 \(\max_{j\le i}(f_{v,j} + j)\),后缀 \(suf_i\),表示 \(\max_{j \le i}(f_j)\)。这样就可以优化到 \(O(n^2)\)

进一步优化,发现转移可以用线段树合并维护。
于是,开一棵值域线段树(以 dp 数组第二维为下标)。每次可以先将 \(u,v\) 的两棵线段树全局加,然后合并。同时在合并过程中维护 \(f_{u,i} + f_{v,j} + j\)
具体的,对于一个叶子,就是 \(f_{u,i} + f_{v,i}+i\)。对于一个区间 \([l,r]\),设它的中点为 \(mid\)

  • 可能是 \(u\) 的左区间与 \(v\) 的右区间,即 \(f_{u,i} + f_{v,j}+i\)
  • 可能是 \(u\) 的右区间与 \(v\) 的左区间,即 \(f_{u,i} + f_{v,j}+j\)
  • 可能是左区间答案
  • 可能是右区间答案

所以对每个区间维护一个 \(\max(f_{u,i} +i),\max(f_{u,i})\) 就可以了。

posted @ 2025-07-22 17:31  GuoSN0410  阅读(6)  评论(0)    收藏  举报