山东暑假集训2025 III
Day 19
搜索
为什么中间几天没有?要么休息要么打比赛。
fzw:我明明是 NOI 2023 金牌,为什么上面写的是 2017?
题目:(由于没有具体题号就简述一下题意)
现在有一个长度是 \(n\) 的包含 \(A\) 和 \(B\) 两种元素的序列,对于一个位置 \(i\),我们把它更改为对面元素(\(A\) 变成 \(B\),\(B\) 变成\(A\)),代价是 \(2^i\)。现在给定一个 \(k\),要求对于任意段,保证 \(cnt_B - k \le cnt_A\)。求出最小代价。
由于是 \(2^i\),我们会发现 \(2^0 + 2^1 + 2^2 + ... + 2^{i - 1} < 2^i\),也就是说,我们要尽可能地改变让最后改变的位置前置。
我们把式子转化一下:\(cnt_B - cnt_A \le k\),那么我们不妨把 \(B\) 看作 \(1\),\(A\) 看作 \(-1\),那么也就变成了最大后缀字段和 \(\le k\),我们只需要从后向前扫,如果实在是不行就改变,记录答案即可。
题目:P3154 [CQOI2009] 循环赛。
我们发现,某个运动员 \(i\),他的得分一定是由若干个 \(3\) 加上若干个 \(2\) 所构成的,我们考虑拆分出来,一个一个去搜索他和剩余的运动员之间的胜负关系,再加一些简单的剪枝,比如说下面的限制、一些不合法的方案直接在第一次找到就返回。
题目:CF949E Binary Cards。
我们会发现一些特别的性质(我感觉每次我一说就是“我们会发现”),具体如下:
- 如果我们选择了 \(a\) 和 \(a\),其实不如选择 \(a\) 和 \(2a\),可以证明,\(a\) 和 \(2a\) 可以凑配出 \(a\) 和 \(a\) 的所有方案,并且还多一个 \(3a\);
- 如果我们选择了 \(a\) 和 \(-a\),本质上不如选择 \(2a\) 和 \(-a\),可以证明,选择 \(2a\) 和 \(-a\) 一定可以凑配出 \(a\) 和 \(-a\) 的所有方案数。
那么,我们得出一个性质:对于每一个数 \(a\),要么选择 \(a\),要么选择 \(-a\),要么不选。
由于 \(a_i\) 很小,所以 \(\log a_i\) 大概也就是 \(20\)。所以我们去搜索每一个 \(2^j\),如果确实存在 \(a_k\) 包含 \(2^j\),那么我们枚举选什么,否则不选。总复杂度是 O(能过) \(O(n \log V)\)。
fzw:我大概新高一的时候过的,所以新高一的小朋友们一定也能过。
于是我们看向了高某。
fzw:清蛙大学
本题思路清奇,建议没玩过扫雷的同学们去玩。
我们首先考虑一个类似于田字的东西,也就是雷把空地分成了几个不连通的连通块。我们只会有选择(\(1\))和不选择(\(0\))两种方式,那么我们直接搜索即可。
接下来考虑如果不是,类似于下面这个东西:

我们会发现在 \((2, 2)\) 这个位置会被 \((1, 1)\) 以及 \((4, 4)\) 都可以更新到(做好准备,我们开始起飞),我们不妨把这个东西记为一个点,像 \((2, 2)\) 这样的中间点看作一条边,把左上的连通块和右下的连通块拼接在一起,再进行搜索。
具体地:对于一个点,如果它是 \(0\),那么对于边没有限制,相当于直接删边即可;如果它是 \(1\),那么它的··边必须是 \(1\),直接记录即可。
题目:P3067 [USACO12OPEN] Balanced Cow Subsets G:见山东暑假集训2025 I。
题目:#750. 【UNR #6】小火车,有点逆天,待补。
fzw:干什么事情都要主动,不仅包括学习,还包括谈恋爱。
贪心
fzw:贪心是一种直觉。
我们:这话咋这熟?xby曾言。
P1954 [NOI2010] 航空管制:
一开始:这不是弱智贪心吗?
过了一会儿:这咋这么难啊!
我们考虑让时光倒流,反向建图,就是把 \(u\) 到 \(v\) 的边改成 \(v\) 到 \(u\) 的边。
如果我们反着走,也就是先找到第 \(n\) 架飞机。由于它可以在 \(n\) 起飞,那么它一定可以在 \(n - 1\),\(n - 2\) 以此类推,所以我们这么找的贪心策略是对的。
考虑第二问,对于一个飞机 \(u\),要是问它最早可以在什么时候起飞,那么转化一下问题,就是多少架飞机在 \(u\) 之前起飞,也就是其他的飞机要尽可能晚的起飞,在图上跑 DAG 即可。
题目:CF1091F。
考虑反悔贪心。
我们贪心的想,如果我们的能量无限多,那么我们呢是不是可以一直飞?
如果当前是草地,我们的速度是 \(5\) 秒代价,飞行时 \(1\) 秒代价,那么我们如果从飞行改过来的话,会有 \(4\) 秒代价换取 \(2\) 点贡献。我们把贡献拆开:\(2\) 秒代价换取 \(1\) 点贡献。
如果我们现在走的是湖,我们的速度是 \(3\) 秒,飞行 \(1\) 秒。我们把飞行改成游泳,会得到 \(1\) 秒代价换取 \(1\) 点能量。
同理,如果我们在碰到岩浆之前从游泳往回走,那么相当于 \(3\) 点时间 \(1\) 个贡献。
那么我们把这些丢进优先队列,每次不够用的话取出最小的时间即可得到答案。
题目:P7221 [JSOI2010] 蔬菜庆典。
我们先考虑什么时候输出 +inf。
我们考虑一个点 \(u\),父亲节点为 \(father\),有两个儿子 \(x\) 和 \(y\)。如果 \(v_x \ne v_y\),我们不妨先进行一次,得到 \(nowv_u = v_{father} + v_x - v_u\),在求出第二次:
也就是说,只要 \(v_y - v_x > 0\),那么一定会无限的向上增长,故答案是 +inf。
我们来看,对于一个差分,\(v_x - v_u\) 和 \(v_u - v_{father}\),我们看和原来的式子,貌似是不是也许可能有概率就是对于这两个位置进行交换。
典题:
P5021 [NOIP 2018 提高组] 赛道修建。
我们一眼二分,答案具有单调性。我们考虑二分一个 \(mid\),也就是去判断能否达到 \(mid\)。
我们对于一个子树内 \(u\),它有 \(x\) 个儿子:\(v_1, v_2, ..., v_x\)。假如我们知道 \(v_a + v_b \ge mid\),那么 \(a\) 和 \(b\) 一定是合法的。
我们考虑进行包含配对(就是说把最左边的和最右边的配对),同时也得向父亲进贡给一个单独的最大的且去掉之后还能保证合法的链。这个我们可以使用二分,二分到第 \(mid1\) 条链,考虑去掉之后匹配是否合法。把最大的 \(mid1\) 向上传即可。
简单题:CF1399E2。
我们考虑把 \(c_i = 1\) 和 \(c_i = 2\) 的分别列出来排序,然后按照双指针的进行匹配即可。
趣题:CF1621F。
我们作为出题人来考虑,我们设置 \(1\) 和 \(3\) 的操作是什么目的?
很明显,如果我们破坏了中间的连续的 \(0\),花费一个 \(3\) 操作,那么我们可以进行很多很多次的 \(2\) 操作。我们可以看出:
- 设置 \(1\) 操作是为了能够进行一些 \(3\) 操作;
- 设置 \(3\) 操作是为了能够进行更多的 \(2\) 操作。
- 设置 \(2\) 操作是为了难为选手。
那么我们就可以进行一些奇怪的操作,得到答案。
Day 20
线段树
fzw:我个人还是很喜欢数据结构的,因为难点在数据结构,不在思维。
题目:CF650D Zip-line。
首先我们考虑设 \(f_i\) 表示区间内以 \(i\) 为结尾的最长前缀上升子序列长度,\(g_i\) 表示已 \(i\) 为结尾的最长后缀下降子序列长度。
如果我们选择这个 \(i\) 作为 LIS 中的一个点,那么我们的最长上升子序列的长度自然就是 \(f_i + g_i - 1\)。
我们考虑一个点 \(i\),如果 \(i\) 处于 LIS 中并且是强制存在的,我们尝试去寻找一个点 \(j\),使得 \(f_i = f_j\) 且 \(j\) 也可以构成一个完整的 LIS,我们就去替代,否则设原答案是 \(k\),那么现在答案就是 \(k - 1\)。
题目:CF1179C。
我们会发现,对于一个 \(pos\),菜品的先后顺序和学生买走的东西无关。我们维护一个区间的后缀第一个 $ > 0$ 的位置 \(pos\),考虑对于这个点进行更改即可。
题目:CF1621E。
和上一道题目类似,我们把老师的年龄看作学生的钱,把平均年龄看作菜价,相当于仅仅把平均年龄进行修改即可。
题目:CF407E。
我们考虑一个区间 \([l, r]\),我们考虑对于每一个 \(a_i\) 变成一个 \(b_i = \frac{a_i - w}{d}\),其中每一个 \(a_i = k_i \times d + w\) 的最大 \(w\)。
对于区间 \([l, r]\),我们考虑使用线段树维护区间的最大值,记为 \(maxn\),区间最小值记为 \(minn\),那么我们只需要判断 \(maxn - minn + 1 \le r - l + 1\) 即可。
题目:CF609F。
我们首先考虑 \(O(nm)\) 的解法,我们会枚举每一只蚊子,考虑对于一个青蛙能否吃到它,直接模拟即可。
我们思考一下这个算法的瓶颈:我们每次都是回去枚举每一只青蛙,那能不能用某种奇奇怪怪的数据结构来进行维护。
我们考虑,如果一个区间 \([l1, r1]\) 和 \([l2, r2]\),满足不等式 \(l1 \le l2, r1 \ge r2\),那么区间 \([l2, r2]\) 是没有用处的,
Day 21
fzw:昨天晚上的 ABC 有人进前 \(20\) 吗?那前 \(40\) 呢?有人过 G 吗?很简单的。这题是数据结构和串串~~
fzw:哇,居然有 \(O(1)\) 个同学影动了
字符串
题目:P8819 [CSP-S 2022] 星战。
不可以,总司令。
我们考虑一个集合 \(A\),我们不妨用一个大质数 \(p\) 对于 \(A\) 进行编号,然后再进行枚举,考虑是否可以达到即可。
题目:CF1599F。
我们考虑在一个区间内 \([l, r]\),假如说它可以构成一个等差数列,那么我们不妨进行一下 hash。
具体来说,对于一个数 \(a\),我们映射成 \(a^k\),这样可以有效的避免冲突且方便计算。
题目:CF319D。
我们会发现:
如果此时有一个串 \(A\),如果删除之后会不会产生一个 \(B\),使得 \(|B| < |A|\)?
答案是否定的。
所以我们考虑枚举每一个长度 \(len\),同时我们知道 \(\sum \frac{n}{i} = O(n \log n)\),所以我们不妨枚举 \(len\) 作为长度,然后我们在 \(len\),\(2\times len\),\(3\times len...\) 的地方设置一个关键点。我们知道,如果一个 \(AA\) 串长度存在,那么一定会跨越一个关键点。所以,我们对于相邻的两个关键点做最长公共后缀和最长公共前缀即可。
KMP
循环节与 \(nxt\) 数组的关系:
我们可以发现 \(n - nxt_n\) 就是 循环节。
记这个数为 \(t\),但是如果 \(t\) 不能整除 \(n\),则字符串无循环节。
弱循环定理:
加入 \(A\) 和 \(B\) 都是字符串 \(S\) 的循环节,则 \(\gcd (|A|, |B|)\) 也是循环节。
题目:AT_arc077_d。
结论好猜,不好证。由于是黑题,直接给出结论,笔者不给出证明。因为没听懂。
结论:如果一个串串 \(A\) 是一个周期的字符串,那么我们会发现会来回翻;但是我们记录 \(A\) 为原串,\(B\) 为最小的周期,那么答案就是:
- \(A(B)\)
- \(AB(A)\)
- \(ABA(AB)\)
- \(ABAAB(ABA)\)
证明?没有。
DP
syk:听 fzw 老师说大家都很厉害,紫题随便秒。
我们:不,他在瞎说。
syk:大家有啥好解法吗?
lzy:DFS。
syk:当你想到DFS,你离 NOI Au 更近了一步。
此时,fzw 突然说话:DFS。
P2051 [AHOI2009] 中国象棋。
我们先转化一下问题,从最多可以放多少个炮,那么也就是每一行、每一列最多只能放置 \(2\) 个炮。
松门设计状态,我们不妨设 \(dp_{i, j, k}\) 表示前 \(i\) 行中有 \(j\) 列放了 \(1\) 个炮、有 \(k\) 列放了 \(2\) 个炮,自然还剩 \(m - i - j\) 列放了 \(0\) 个炮。下面即将进行逆天的分类讨论。
- 如果这行不放,那么答案就是 \(dp_{i - 1, j, k}\);
- 如果这行放一个,且放在原来是 \(1\) 个炮上,那么答案就是 \(dp_{i - 1, j + 1, k - 1} \times (j + 1)\);
- 如果这行放一个,且放在原来是 \(0\) 个炮上,那么答案就是 \(dp_{i - 1, j - 1, k} \times [m - (j - 1) - k]\);
- 如果这行放两个,且这两个都放置在原来 \(1\) 个炮上,那么答案就是 \(dp_{i - 1, j + 2, k - 2} \times C_{j + 2}^{2}\);
- 如果这行放两个,且这两个都放在原来 \(0\) 个炮上,那么答案就是 \(dp_{i - 1, j - 2, k} \times C_{m - (j - 2) - k}^{2}\);
- 如果这行放两个,且这两个一个放在 \(0\) 上,一个放在 \(1\) 上,那么答案就是 \(dp_{i - 1, j, k - 1} \times j \times [m - (k - 1) - j]\)。
综上,把上面的所有式子加起来即可。
题目:P2467 [SDOI2010] 地精部落。
我们考虑设计一下状态:我们设 \(dp_i\) 表示一个 \(1\) 到 \(i\) 的排列按照山峰开头的方案数。我们知道,最终的答案就是 \(2 \times dp_n\)。
我们考虑如何进行转移:
因为 \(i\) 一定是这个排列中最大的数,所以不管 \(i\) 放在哪里都会形成一个山峰且 \(i\) 所在的位置一定是个奇数。
我们考虑把 \(i\) 放在 \(j\) 这个位置:那么 \(j\) 前面一共有 \(j - 1\) 个位置,后面又 \(i - j\) 个位置。
我们又知道,前 \(j - 1\) 个数只与他们的数量关系有关,和具体数值无关,所以我们不妨再视作一个排列,那么答案就是 \(\sum dp_{j - 1} \times C_{i - 1}^{j - 1} \times dp_{i - j}\),其中 \(j\) 是奇数。
题目:P1437 [HNOI2004] 敲砖块。
我们不妨考虑一下我们要是选择 \((i, j)\) 这个位置,哪些位置一定会被选到。
肯定是以 \((i, j)\) 为顶点的一个等腰直角三角形。
我们不妨把整个三角形逆时针旋转 \(90°\),旋转出来的三角形是从左边开始选的。
我们不妨观察一下轮廓线,发现这一行的选择的一定是不超过上一行的个数 \(+ 1\) 的。所以我们一次开始设计状态:
我们设 \(dp_{i, j, k}\) 表示前 \(i\) 行在第 \(j\) 处为转折点一共打了 \(k\) 个砖头的最大值。
我们来进行一下小小的转移:
其中,\(l \ge j - 1\),\(s_{i, j}\) 表示第 \(i\) 行前 \(j\) 个数的和。
题目:P6189 [NOI Online #1 入门组] 跑步:见山东暑假集训 I,此处补充:这两个转移方程都是完全背包的变形。
CSP真题哦~~
这道题目很直接,我们不妨直接设计一个 DP 状态:\(dp_{i, 0/1}\) 表示前 \(i\) 个数中并且强制第 \(i\) 个数是 \(0\)(红色)或者是 \(1\)(蓝色)。
我们先考虑一个 \(lst_i\) 表示上一个 \(a_{lst_i} = a_i\),我们考虑希望让这两个颜色相同,那么我们肯定希望 \(lst_i + 1\) 到 \(i - 1\) 是另外一种颜色。
我们同时记录一个 \(s_i\) 表示 \(1\) 到 \(i\) 都是是一个颜色的方案数。可以证明,这是一个可以前缀和的。
那么我们可以直接对于 \(dp_{i, 0/1}\) 通过判断 \(dp_{i - 1, 0/1}\) 和 \(dp_{lst_i + 1, 0/1} + s_i - s_{lst_i + 1}\)。
题目:P7962 [NOIP2021] 方差。
和之前的某一道题目很像,我们会发现这个东西本质上就是对于相邻的差分数组进行了交换。所以,我们只对于差分数组进行排列及求解即可。
我们考虑差分序列,很明显(貌似也不是那么明显),我们肯定希望尽可能多的数位于平均数附近。
也就是说,这个数组一定会是先上升的很快,然后很慢,然后又很快。
类似的,差分数组也会是先单调递减,后单调递增(感觉和导数有点像啊)。
所以,我们对于差分数组进行排序,然后我们考虑 \(i\) 这个位置现在是加入左边还是右边。
这里引入一个数学公式:\(s^2 = \frac{(\sum a_i)^2}{n} - (\frac{\sum a_i}{n})^2\)。
我们现在考虑如果加入左边的可能出现的值大还是右边可能出现的值大,进行比较即可。
典中典:P1896 [SCOI2005] 互不侵犯。
我们考虑进行状态压缩DP,设状态 \(dp_{i, j, k}\) 表示前 \(i\) 行中,第 \(i\) 行的压缩状态是 \(j\),一共放了 \(k\) 枚棋子的总方案数。
我们考虑进行转移,假设第 \(i - 1\) 行的状态是 \(t\),假设 \(j\) 与 \(t\) 均合法且 \(t\) 和 \(j\) 能够做到互不侵犯,那么我们可以直接得到这一行放了多少个国王,并利用刷表法进行转移:
Day 22
DP,依旧是DP。
题目:P5933。
我们设 \(f_S\) 表示 \(S\) 这个集合强制联通的方案数。我们发现这个状态并不好转移,所以我们考虑正难则反,设 \(h_S\) 表示不论 \(S\) 是否联通的总方案数,\(g_S\) 表示 \(S\) 强制不连通的方案数,我们会发现一个恒等式:\(f_S + g_S = h_S\)。
我们发现 \(h_S\) 是可以直接算出来的。,\(h_S = \prod {c_{i, j} + 1}\)
我们考虑如何转移 \(g_S\),我们设 \(u\) 表示点集中最小的那个点,我们要枚举所有的 \(T\),使得 \(T\) 既是 \(S\) 的真子集又必须包含 \(u\)。
我们会发现,\(u\) 所在的连通块必须强制联通,剩下的点我们不管,设 \(D\) 是 \(T\) 的关于 \(S\) 的补集,那么答案就是:
这是以上的式子之和。
题目:P7519。
这才是真正的拼好题。
我们贪心地考虑,对于一个 \(b\) 序列,如果:
- \(a_i \ge a_{i - 1}\),则 \(b_i = b_{i - 1}\);
- \(a_i < a_{i - 1}\),则 \(b_i = b_{i - 1} + a_{i - 1} - a_i\)。
我们可以发现规律:\(b_i = b_{i - 1} + \max(0, a_{i - 1} + a_i)\)。
我们把式子加起来,我们会发现:
我们再进行 DP,我们设 \(dp_{S, i, j}\) 表示现在压缩的状态是 \(S\),考虑前 \(i\) 个人,现在的总花费是 \(j\),那么我们进行转移:
考虑一个 \(k\),表示现在第 \(k\) 个人代替 \(i\) 作为新的第一名,那么现在的 \(T\) 是 \(S | (1 << k)\),第 \(k\) 个人,花费是 \(j + \max(0, a_i - a_k) \times (n - i + 1)\),直接转移即可。
简单题:P4302。
我们考虑,不是,这么典还考虑啥啊,直接 DP得了!
我们设 \(dp_{l, r}\) 表示 \([l, r]\) 的答案。
我们考虑这三条关系:
- \(dp_{l, r} = r - l + 1\)
- \(dp_{l, r} = \min dp_{l, k} + dp_{k + 1, r}\)
- \(dp_{l, r} = \min dp_{l, k} + 2 + \lg(r - l + 1)\),其中规定 \([l, k]\) 是循环节
我们如果直接枚举的话复杂度会爆炸,大概是 \(O(n ^ 4)\),我们考虑优化。发现 \(k - l + 1\) 一定是 \(r - l + 1\) 的因数,我们直接枚举因数即可,复杂度优化到 \(O(n ^ 3 \log n)\)。
题目:P4170。
我们直接按照两种方法进行转移:
对于区间 \([l, r]\),如果中间存在断点,那么
另外,如果 \(s_l = s_r\),那么
没了。
题目:P6879。
我们如果直接正着设计状态会发现这并不好设计,于是我们反向设计:
我们设 \(dp_{l, r, 0/1, k}\) 表示 \([l, r]\) 区间中现在站在 \(l\) (就是 \(0\))还是 \(r\) (就是 \(1\)),打卡 \(k\) 个点的花费时间。
我们考虑进行转移,假如说 \(l\) 这个位置不是在边界上,那么它还可以向左移动,如果我们加上新的时间之后形成的 \(newt\) 是否合法,再进行更新即可。
题目:P4572。
我们考虑二分,二分一个 \(k\),再进行 DP 即可。
我们设 \(dp_u\) 表示 \(u\) 被保护的需要祖先节点的保护的次数。
我们首先 \(dp_u = \sum dp_v + 1\),同时我们 \(dp_u\) 还得剪掉一个 \(k\),最后判断 \(dp_1\) 是否等于 \(0\) 即可。
题目:P7077。
我们考虑如果没有第三种操作,只有前两种操作,我们会怎么做。
假设我们进行以下的操作:
我们考虑从后往前走,先看到 \(+ 2\),发现倍率是 \(1\),所以我们本质上加上的其实是 $ + 2$;我们又看到 \(\times 2\),此时我们将倍率乘上 \(2\);我们再向前看,如果 $ + 3$,本质上其实加上的是 \(2 \times 3 = 6\);在看到前面,$ + 1$,那么实际上加上的其实是 \(1 \times 2 = 2\)。我们把原来的加起来,那么得到 \(2 + 6 + 2 = 10\)。
同理,我们把这个调用函数当作一个拓扑结构,得到的拓扑序列之后我们一次考虑这个位置 \(u\) 以及它的子树内,算出子树内的乘积,从后向前走即可。
浙公网安备 33010602011771号