【杂题】2 月做题记录

2022.2.11

P3749 [六省联考 2017] 寿司餐厅

题目链接

我们将每种 \(d_{i,j}\) 的收益都看做一个物品。显然如果选择 \(d_{i,j}\)\(i<j\)),则必须选择 \(d_{i,j-1}\) 以及 \(d_{i+1,j}\)

而如果吃了 \(c\)\(c>0\))种类型为 \(x\) 的寿司,需要付出 \(mx^2+cx\) 的代价。
这可以转化为:吃了每种类型为 \(x\) 的寿司需要付出 \(x\) 的代价,而吃过类型为 \(x\) 的寿司需要付出 \(mx^2\) 的代价。

选择了 \(d_{i,i}\) 就代表吃掉了第 \(i\) 种寿司,这时需要付出 \(a_i\) 的代价(\(a_i\) 是这种寿司的类型)。

选择了 \(d_{i,i}\) 还意味着:必须付出 \(m\cdot a_i^2\) 的代价,我们将每个寿司类型也看作一个物品,选择收益 \(d_{i,i}\) 则必须选择类型 \(a_i\)

至此,所有限制都转化为了“选择 \(x\) 则必须选择 \(y\)”的形式,可以使用最大权闭合子图的模型解决了。

P3825 [NOI2017] 游戏

题目链接

需要注意的一些点:

  • 对于限制若 \(x_i=p\) 一定有 \(x_j=t\) ,一定要建两条边 (两个限制)

    • \(x_i=p\) 一定有 \(x_j=t\)
    • \(x_i=p\oplus 1\) 一定有 \(x_j=t\oplus 1\) ,其中 \(\oplus\) 表示异或
  • 对于限制 \(x_i\) 一定等于 \(p\) 可以这样建边:

  • \((i,p)\to(i,p\oplus 1)\)

2022.2.12

P4093 [HEOI2016/TJOI2016]序列

题目链接

考虑令 \(f[i]\) 表示以 \(i\) 结尾的满足条件的最长子序列长度。

一个合法的转移点 \(j\) 必须在任意操作的影响下满足 \(a_j\le a_i\),因为所有未影响 \(i,j\) 的操作都不用考虑,所以转移点 \(j\) 合法的充要条件是:

  • \(maxval_j\le a_i\)

  • \(a_j\le minval_i\)

其中 \(maxval_k\) 表示第 \(k\) 个位置能变成的最大值,\(minval_k\) 表示第 \(k\) 个位置能变成的最小值。

因为 DP 更新的顺序提供了天然的时间轴,所以考虑按时间轴分治处理 DP,注意要先递归处理左半边然后处理左半边对右半边的贡献再递归处理右半边。

复杂度 \(O(n\log ^2 n)\)

P2824 [HEOI2016/TJOI2016]排序

题目链接

考虑一个弱化版的问题:序列中只有 \(0\)\(1\)

那么我们发现可以使用线段树维护区间 \(1\) 的个数以及区间推平操作即可。

那么我们可以每次二分答案,将 \(< x\) 的置成 \(0\)\(\ge x\) 的置成 \(1\) 之后做只有 \(0\)\(1\) 的问题即可。

P3746 [六省联考 2017] 组合数问题

题目链接

问题等价于从 \(nk\) 个物品中选恰好 \(j(j\equiv r\pmod k)\) 个物品的方案数。

\(f[i,j]\) 表示从前 \(i\) 个物品中选恰好 \(t(t\equiv j\pmod k)\) 个物品的方案数,有转移方程:

\[f[i,j]=f[i-1,j]+f[i-1,(j-1)\bmod k] \]

那么:

\[\begin{aligned} f[i+1,j]\gets f[i,j]\\ f[i+1,(j+1)\bmod k]\gets f[i,j] \end{aligned} \]

因为 \(r\)\(k\) 很小,所以考虑使用矩阵快速幂加速。

\(\forall j\in [0,k)\),令转移矩阵 \(M[j][j]\gets 1,M[j][(j+1)\bmod k]\gets 1\)

复杂度 \(O(k^3\log nk)\)

CF1637E Best Pair

题目链接

首先有一个自然根号,\(\sum_{i=1}^{\sqrt{n}}i=O(n)\)

那么意味着在长度为 \(n\) 的序列中,不同的 \(cnt[x]\) 的个数是 \(O(\sqrt{n})\) 级别的。

考虑将所有权值 \(val\) ,按 \(cnt[val]\) 分类,一共可以分 \(O(\sqrt{n})\) 组,令第 \(i\) 组为 \(buc_i\) ,对应的 \(cnt\)\(cnt(buc_i)\)

枚举点对 \((i,j),i\le j\),考虑从组 \(buc_i\) 选一个权值,从组 \(buc_j\) 选一个权值构成的最大价值。其中枚举点对的复杂度是 \(O(\sqrt{n}\times \sqrt{n})=O(n)\) 的。

如果没有不能选钦定的权值对的限制,那么就是从 \(buc_i\) 选一个最大的权值,\(buc_j\) 选一个最大的权值。

做法 1

而考虑钦定的权值对,一个暴力的想法是将在 \(buc_i,buc_j\) 组的所有权值从大到小排序,从大到小枚举 \(buc_i\) 中的权值与 \(buc_j\) 中的匹配。

这样的复杂度是 \(O(n\sqrt{n}\log m+m\log m)\) 的(类似 CF1574D)。

一个神秘改进:钦定 \(cnt(buc_i)\ge cnt(buc_j)\)

做法 2

预处理所有组的对 \(i,j\) 之间 ban 掉的边。

如果当前枚举的是第 \(i\) 组和 第 \(j\) 组,处理出一个点集 \(S\) ,其中的任意一个点 \(t\) 满足:在第 \(i\) 组,且存在一条被 ban 的边 \((t,p)\) 满足 \(t\) 在第 \(i\)\(p\) 在第 \(j\) 组。

将第 \(i\) 组的点分成两类,一类是点集 \(S\) 中的,一类是未在点集 \(S\) 中的。

分别处理两类点与第 \(j\) 组的贡献。

对于点集 \(S\) 中的点 \(t\) 与第 \(j\) 组的贡献,考虑一个点集 \(to[t]\), 其中的点 \(p\) 满足在第 \(j\) 组且存在一条被 ban 的边 \((t,p)\)

我们要求的即第 \(j\) 组中最大的,不在 \(to[t]\) 中的点,是个 mex 类状物,可以在 \(O(|to[t]|)\) 的复杂度内求出。

而对于未在点集 \(S\) 中的点只需要求出这个点是哪个点即可,也是一个 mex 类状物,可以在 \(O(|S|)\) 的复杂度内求出。

处理两组 \(i,j\) 之间的贡献的复杂度是两组之间的边数级别的。

复杂度是 \(O(n+m\log m)\)

2022.2.13

P4630 [APIO2018] Duathlon 铁人两项(口胡)

题目链接

圆方树板题,建出圆方树后 DP 一下就行了。

圆方树结构与点双连通分量结构:

  • 对于一个点双中的两点,它们之间简单路径的并集,恰好完全等于这个点双
  • 圆方树上两个圆点简单路径上的圆点是不是原图中两个点简单路径的必经点
  • 考虑两圆点在圆方树上的路径,与路径上经过的方点相邻的圆点的集合,就等于原图中两点简单路径上的点集

Loj #3254. 「JOI 2020 Final」集邮比赛 3

题目链接

首先可以破环成链,将环拆成两段序列。

那么收集过程中在环上的路径,就可以映射成序列上的路径。

并且路径上经过的点一定是前面一段序列的一个后缀并上后面一段序列的前缀。

而不难发现,对于一个位置上的邮票如果第一次经过没有收集到,那么之后每一次经过都不会收集到,因此考虑枚举路径时在第一次经过某个位置时计算该位置上的邮票的贡献。

因此一个朴素的 DP 是令 \(f[i,j,k,0/1]\) 表示当前已经经过左边段的后 \(i\) 个位置,右边段的前 \(j\) 个位置且恰好走了 \(k\) 步,当前在左边段倒数第 \(i\) 个位置 / 右边段正数第 \(j\) 个位置最多能拿多少张邮票。

而对于有花费限制的最大收益问题,可以考虑将 DP 状态中的花费替换为收益,去 DP 最小花费而不是最大收益。

因此考虑令 \(f[i,j,k,0/1]\) 表示当前已经经过左边段的后 \(i\) 个位置,右边段的前 \(j\) 个位置且恰好拾取了 \(k\) 张邮票,当前在左边段倒数第 \(i\) 个位置 / 右边段正数第 \(j\) 个位置,最少的总步数。

而每次转移只需要向左 / 右更新一次(区间 DP 取一端)。

复杂度 \(O(n^3)\)

Loj #3255. 「JOI 2020 Final」奥运公交

题目链接

注意到,将一条边 \(u\to v\) 取反后从 \(1\)\(n\) 的最短路等于:

  • 不经过边 \(u\to v\) 的从 \(1\)\(n\) 的最短路

  • 不经过边 \(u\to v\) 的从 \(1\)\(v\) 的最短路 + 边权 + 不经过边 \(u\to v\) 的从 \(u\)\(n\) 的最短路

\(n\)\(1\) 的也同理:

  • 不经过边 \(u\to v\) 的从 \(n\)\(1\) 的最短路

  • 不经过边 \(u\to v\) 的从 \(n\)\(v\) 的最短路 + 边权 + 不经过边 \(u\to v\) 的从 \(u\)\(1\) 的最短路

那么我们可以转化为常数个下面的问题:

  • 给定一个图,\(m\) 条边,对于每条边求不经过该边的从源点 \(s\) 到点 \(u(1\le u\le n)\) 的最短路。

考虑建出以源点 \(s\) 为根的最短路树,对于不在最短路树上的边答案显然就是从点 \(s\) 到点 \(u\) 的最短路,而对于在最短路树上的边可以暴力删边重新跑最短路,因为最短路树有至多 \(n-1\) 条边,所以这部分的复杂度是 \(O(n(n^2+m))=O(n^3+nm)\) 的(这里采取朴素 dijkstra 算法)。

对于本题可以通过。

那么本题只需要建四棵最短路树即可,

令原图为 \(G\),反图为 \(G'\)

  • \(G\) ,源点为 \(1\) 建最短路树
  • \(G'\),源点为 \(n\) 建最短路树
  • \(G\),源点为 \(n\) 建最短路树
  • \(G'\),源点为 \(1\) 建最短路树

CF555E Case of Computer Network(口胡)

题目链接

引理:给一张无向图定向后可以变成强连通图当且仅当这张图是一张边双连通图。

e-DCC 缩点之后树上差分即可。

Loj #2350. 「JOI 2018 Final」月票购买

题目链接

注意到,确定了一条从 \(S\)\(T\) 的免费路径后,从 \(U\)\(V\) 的最短路径与该路径的交一定是一条链,即不存在如下情况:

因为将分叉的部分调整一致后一定更优。

求出所有可能成为 \(S\)\(T\) 的最短路上的边,把它们按照 \(S\to T\) 方向定向,建立分层图,第一层和第三层就是原图,第二层是定向后的那些边( \(0\) 权),每个点向下一层的同一个点连边,这样可以保证如果经过变成 0 权的那些边,一定是只会经过一条有向链,然后求 \(U\to V\) 的最短路,注意还需要按照 \(T\to S\) 方向定向一次,因为 \(U\to V\) 经过的那些边可能是与 \(S\to T\) 反向的。

2022.2.15

[JOI 2022 Final] 让我们赢得选举

题目链接(Loj)

因为:

\[\min(\dfrac{a}{b},\dfrac{c}{d})\le \dfrac{a+c}{b+d}\le \max(\dfrac{a}{b},\dfrac{c}{d}) \]

所以一定不存在多个人在不同州同时演讲的情况。集中力量办大事!

并且在最优解中,一个州 \(i\) 的演讲时长要么是 \(0\) ,要么是 \(A_i\)\(B_i(B_i\not= -1)\)

考虑当前已经确定了每个州的演讲时长,确定一种演讲顺序使得时间最短。

因为每次一定是 Rie 和所有的合作者在同一个州演讲,所以时间就是每个州的演讲时长的带权和(演讲时长除以演讲人数)。

如果一个州的演讲时长是 \(A_i\) 称该州为 “合作州”,如果一个州的演讲时长是 \(B_i\) 称该州为 “支持州”,如果一个州的演讲时长为 \(0\) 称该州是 “反对州”。

那么考虑确定一种演讲的顺序使得带权时间和最小,任意一个 “合作州”一定不会在 “支持州”之前进行演讲。

然后考虑 “支持州” 之间的顺序,根据排序不等式(顺序和>=乱序和>=反序和)一定是按 \(B_i\) 排序后从小到大的顺序演讲最优。

那么我们只需要确定“合作州”的个数,“合作州”与“支持州”都是那些州就能够唯一确定该条件下的最优解了。

那么一个朴素的做法是将所有州按 \(B\) 排序,枚举 “合作州” 个数,然后去做 \(O(n^3)\) 的 DP \(f[i,j,k]\) 为前 \(i\) 个州中有恰好 \(j\) 个 “合作州” \(k\) 个“支持州”的最小时间。

但是我们可以发现最优解中最后一个 “合作州”与其前一个 “合作州” 之间的所有州一定是 “支持州”,因为如果之间存在一个 “反对州”,将最后一个 “合作州” 移动到该州一定更优。

进而可以推出:第 \(i\) 个“合作州”与第 \(i+1\) 个“合作州”之间的所有州均是 “支持州”。

那么我们可以将 \(O(n^3)\) 的 DP 简化成 \(O(n^2)\) 的 DP \(f[i,j]\) 表示前 \(i\) 个州中选恰好 \(j\) 个 “合作州” 的最小花费。

本题中 \(O(n^4)\) 做法中外层枚举选多少个 “合作州” 的部分是不能去掉的,因此可以考虑从内层的 DP 中优化。而 \(O(n^3)\) 状态中 “支持州”数量可以利用题目性质优化掉。

Loj #3665. 「JOI 2022 Final」铁路旅行 2

题目链接(Loj)

对于 \(1\le N,M,Q\le 2000\) 的部分分可以考虑维护出从站点 \(i\) 通过 \(\le j\) 条路线可以到达的站点集合,可以使用归纳法证明能够到达的站点集合一定是一段区间 \([l,r]\) 满足\(l\le i\le r\)

而对于 \(K=N-1\)\(A_j<B_j,S_k<T_k\) 的部分分可以使用倍增优化。

因此考虑使用倍增优化 \(1\le N,M,Q\le 2000\) 的部分分做法,令 \([left[i][j],right[i][j]]\) 表示从点 \(j\) 通过 \(\le 2^i\) 条铁路可以到达的站点集合。

有转移方程:

\[left[i][j]=\min_{k\in [left[i-1][j],right[i-1][j]]}(left[i-1][k]) \]

\[right[i][j]=\max_{k\in [left[i-1][j],right[i-1][j]]}(right[i-1][k]) \]

使用线段树优化,预处理的复杂度为 \(O(N\log ^2 N+M)\)

对于每次询问倍增查询即可,复杂度 \(O(Q\log^2 N)\)

CF1637F Towers(代码待补)

题目链接

注意到一定要有一个点放了新号强度恰好为 \(\max\limits_{i=1}^n(h[i])\) 的塔,并且最优解信号强度最大的塔的强度一定恰好是 \(\max\limits_{i=1}^n(h[i])\)

钦定一个点放信号强度为 \(\max\limits_{i=1}^n(h[i])\) 的塔,令这个点为根。

那么限制就转化成了:对于每个点 \(u\) ,子树内一定要存在一个塔满足强度 \(\ge h[u]\)

然后进行一个 DP,令 \(f[u]\) 表示考虑以 \(u\) 为根的子树中的点的最小代价。

如果 \(u\) 所有儿子的子树内的最大值 \(mx\ge h[u]\),那么只需要满足儿子子树的要求即可,并且这里两个不同的儿子的子树互不影响。

如果 \(mx<h[u]\) ,那么在放 \(mx\) 的塔那里将这个塔的强度提升为 \(h[u]\) 即可。

换根去做这个 DP 即可。

我没想到的点:提升强度而不是建新塔。

T225483 C. 定向【省选计划 · 模拟赛 #2】

题目链接

对于 DAG 计数,可以考虑枚举入度为 \(0\) 的点的集合。

\(dp(S)\) 表示集合 \(S\) 内的点构成 DAG 的给边定向的方案数。

钦定一些点,使其入度为 \(0\) ,容斥一下,其中 \(E_{A,B}\) 表示集合 \(A,B\) 之间的边。

\[dp(S)=\sum_{T\ne \empty,T\subseteq S} (-1)^{|T|-1}2^{E_{T,S-T}}dp(S-T) \]

考虑入度为 \(0\) 的点构成的集合恰好是 \(T\) 的每种方案会被算多少次:

\[\sum_{i=1}^{|S|}\binom{|S|}{i}(-1)^{|T|-1}=1 \]

容斥的重要理论基础:

\[\sum_{i=0}^n\binom{n}{i}(-1)^i=0 \Rightarrow \sum_{i=1}^n\binom{n}{i}(-1)^i=-1\Rightarrow\sum_{i=1}^n\binom{n}{i}(-1)^{i-1}=1 \]

\(E_S\) 表示集合 \(S\) 内部的边,那么 \(E_{S,S-T}=E_S-E_T-E_{S-T}\)

暴力计算的复杂度是 \(O(3^n)\) 的,可以使用子集卷积加速,但我不太懂。

2022.2.16

Comet OJ - Contest #14 D(口胡,有时间写一下代码)

考虑序列每个时间在每个时刻的颜色,这里变为二维平面。

对于操作序列第 \(i\) 个位置对应的区间,假设这个区间是对 \([l,r]\) 染色为 \(x\)

那么对于这个平面的贡献是一个 \(\mathrm{3-side}\) 矩形,如图 \(x\) 轴为时间 \(y\) 轴为序列。

这些 \(\mathrm{3-side}\) 矩形可以切分成 \(O(m)\) 个互不相交的 \(\mathrm{4-side}\) 矩形。

这里的切分对应了一个颜色段均摊。

原来的问题是考虑所有左边界在 \([x,y]\) 范围内的矩形的影响查一列的和。

那么可以发现对矩形进行切分后仍然等价于考虑所有左边界在 \([x,y]\) 范围内的矩形查一列的和。

那么接下来只需要考虑每个 \(\mathrm{4-side}\) 矩形对答案的贡献即可。

这里考虑另外一个二维平面,二维平面中点 \((x,y)\) 的权值等于询问的区间为 \([x,y]\) 的答案。

那么对于一个 \(\mathrm{4-side}\) 矩形 \([x_1,y_1]\times [x_2,y_2]\),会对 \([1,x_1]\times [x_1,y_1]\) 产生 \((y_2-x_2)\times col\) 的贡献。

[Ynoi????] TEST_109

注意到到,对一个查询操作产生影响的有且仅有时间维上该查询操作前第一个覆盖查询位置的区间推平操作。

如果没有交换操作考虑倒着扫操作序列,对于每个查询操作找到会对其产生影响的区间推平操作。

而对答案的贡献就是一个矩形加。

那么接下来考虑如何找到会对其产生影响的区间推平操作。

并且这个做法在找对应的区间推平操作时可以支持维护交换。

P7406 [JOI 2021 Final] 集合写真

题目链接

\(pos[h[i]]=i\),一个直接的 \(O(n^2\times n!)\) 的暴力是考虑枚举结果排列 \(p\),然后计算序列 \(pos[p_1],pos[p_2],...,pos[p_n]\) 中的逆序对个数 \(cnt\)\(cnt\) 即为将序列 \(h[]\) 通过交换操作“调整”成排列 \(p\) 的最小操作次数(不懂的话可以左转 P1966 [NOIP2013 提高组] 火柴排队)。

考虑依次把 \(1,2,3,...,n\) 填到 \(n\) 个格子上去“构造合法排列”。

考虑把 \(1,2,3,...,i\) 填到格子上,因为大于等于 \(i+2\) 的数是不能填到 \(1,2,3...,i\) 前面的,而 \(i+1,i+2,...,n\) 这些数中有且仅有 \(i+1\) 能够填到 \(i\) 的前面,那么意味着把 \(1,2,3,...,i\) 填到格子上后,\(1,2,3,...,i\) 这些数中至多有一个数前面有空格子,并且这个数一定是 \(i\)

比如在 \(n=10,i=5\) 时,在把 \(1,2,3,4,5\) 填到格子中后,有且仅有 \(5\) 前面有空格子。

那么把 \([1,i]\) 填到格子中后一定是如下的形式:

即一段前缀全是数(可能这段为空),接一堆空格,再接一段连续的数,并且这个数的开头是 \(i\)(这一段也可能为空)。

但是我们发现这样并不能很快的在 DP 枚举方案的时候确定方案的花费。

但是我们进一步发现,\(i\) 后面只能接 \(i-1\),而如果 \(i\) 后面接了 \(i-1\),那么 \(i-1\) 后面只能接 \(i-2\)

设绿色段的长度为 \(j\),红色段的长度为 \(i-j\),那么红色段一定是 \(i,i-1,...,i-(i-j)+1\)。而绿色段由 \(1,2,3,...,j\) 构成。

那么考虑一个 \(O(n^3)\) 的暴力 DP,令 \(f[i,j,k]\) 表示考虑将 \(1,2,...,i\) 填到格子中,恰好填了长度为 \(j\) 的前缀(即绿色部分的长度为 \(j\)),且 \(i\) 填到格子 \(k\) 中的所有方案中,花费最小是多少。

这里“花费”定义为将 \(1,2,...,i\) 填到格子后,将所有有数的格子拼接成一个长度为 \(i\) 的序列 \(a[]\),序列 \(pos[a[1]],pos[a[2]],...,pos[a[i]]\) 的逆序对个数。

\(suf[i,k]=\sum_{j=i-k}^{i-1}[pos[j]<pos[i]],pre[i,k]=\sum_{j=1}^k[pos[j]>pos[i]]\)

如果 \(j=i\)

\[f[i+1,j+1,j+1]\gets f[i,j,k]+pre[i+1,i] \]

如果 \(j\not= i,k=j+2\)

\[f[i+1,i+1,k-1]\gets f[i,j,k]+pre[i+1,j]+suf[i+1,i-j] \]

如果 \(j\not =i,k\not= j+2\)

\[f[i+1,j,k-1]\gets f[i,j,k]+pre[i+1,j]+suf[i+1,i-j] \]

同时对于 \(k\ge i+2\)\(k\) 有转移:

\[f[i+1,j,k]\gets \min_{t}(f[i,i,t])+pre[i+1][i] \]

配合滚动数组技巧优化空间,可以拿到 64 分。

但是实际上可以发现第三维可以直接去掉,因为我们并不在意 \(i\) 具体是在哪个格子,只要确定了前缀的长度 \(i\) 在哪费用都是一样的。

因此可以直接令 \(f[i,j]\) 表示考虑将 \(1,2,...,i\) 填到格子中,恰好填了长度为 \(j\) 的前缀(即绿色部分的长度为 \(j\)) 的所有方案中,花费最小是多少。

转移类似上面的暴力 DP。

复杂度 \(O(n^2)\)

做法 2

由上一个做法推出的结论可以引出一个更强的结构,任意一种合法的排列一定是若干段“连续值域下降段”拼接而成的,即一定是由形如 \([5,4,3,2],[10,9,8],[6,5,4,3]\) 这种段拼接而成。

那么考虑令 \(f[i]\) 表示由 \(1\sim i\) 构成的合法排列中,最小花费是多少。

另一种考虑方式实际上是考虑最终的结果中,一个元素 \(i\) 的后继如果小于该元素,那么只有可能是 \(i-1\),进而可以将最后的结果序列看成若干段连续下降段拼接而成。

P7405 [JOI 2021 Final] 雪玉

题目链接

注意到,所有的雪球一定都是同时移动的。

那么对于第 \(i\) 个雪球,最终会对第 \(i\) 个雪球产生贡献的边一定是连续的一段边。

考虑维护出第 \(i\) 个雪球左右两边各有多少条边会对其产生贡献。

暴力维护的复杂度为 \(O(nq)\)

但是接下来可以注意到一个重要的性质,所有雪球的位移是相同的,因此可以维护所有雪球在前 \(i\) 个操作中的最大位移和最小位移。

如果当前时刻的位移未成为最大位移 / 最小位移,那么这个操作显然是不会对任何一个雪球的重量产生贡献的。

可以考虑用一个 set 维护所有相邻雪球的段,维护每个段对左边的雪球和右边的雪球产生多少贡献,每次删除掉贡献“满了” 的段(即给左边雪球的贡献 + 右边雪球的贡献 = 段长) 的段,可以打标记维护当前 set 中所有段对左边雪球的贡献和对右边雪球的贡献,因为每个段被删除至多一次,因此是均摊 \(O(n\log n)\)的。

2022.2.17

P7407 [JOI 2021 Final] ロボット

题目链接

考虑枚举一条从 \(1\)\(n\) 的路径,将路径上的所有边定向。

求出为了满足“存在一种让机器人恰好走的路径为该路径的指令”改颜色的最小花费。

对于路径上的每条边 \(u\to v\) ,设其颜色为 \(col\), 有以下两组决策:

  • 将该边的颜色改成与点 \(u\) 相连的所有的边中未出现过的颜色

  • 将除了该边以外的,与点 \(u\) 相连的边中所有颜色为 \(col\) 的边的颜色改掉(如果不存在则不用改)

我们考虑按从 \(1\)\(n\) 的顺序依次去决策每条边改颜色,决策到边 \(u\to v\) 时需要注意如果使用第二种决策,如果前一条边 \(x\to u\) 修改后的颜色与 \(u\to v\) 的颜色相同,需要将 \(x\to u\) 改为与点 \(x\) 相连的所有的边中未出现过的颜色。

那么不难发现,对于每条边无论是选第一种和第二种决策,都能够构造出合法的方案。

但是我们需要注意下面的情况:

如果路径上存在连续两条颜色相同的边,那么如果对第二条绿边进行第二种决策时可以顺便决策第一条绿边变的颜色,而这样是不需要额外的花费的。

因此我们还要考虑这种情况。

这里采用 “虚点” 去描述决策。

对于点 \(u\) 连出的所有颜色为 \(col\) 的边,拆成两个点,分别表示上面的两种决策。

同时对于每条边也拆出一个点表示第三种决策向对应的位置连边即可。

建图之后跑最短路即可。

P4064 [JXOI2017]加法

题目链接

考虑二分答案,从而可以求出每个位置至少被覆盖多少次。

而对于恰好选 \(k\) 个区间,可以转化成选至多 \(k\) 个区间,进而考虑求出最少使用多少个区间使得对于任意位置 \(i\) ,被覆盖至少 \(limit[i]\) 次。

从左到右扫每个位置,假如当前扫到了 \(i\), 考虑所有当前未被选的满足 \(l_j\le i\le r_j\) 的区间 \(j\)

按右端点从大到小依次选择区间,直到位置 \(i\) 被覆盖了 \(limit[i]\) 次。

对于证明可以考虑使用决策包容性进行调整法。

在贪心的过程中用树状数组维护每个位置被覆盖了多少次即可。

复杂度 \(O(n\log ^2 n)\)

P4065 [JXOI2017]颜色

题目链接

考虑枚举最后剩下的区间 \([l,r]\),令 \(fst[i]\) 表示 \(a[i]\) 第一次出现的位置,\(lst[i]\) 表示 \(i\) 最后一次出现的位置。

那么剩下的区间 \([l,r]\) 合法当且仅当对于任意的 \(i\in [l,r]\) 满足 \(fst[a[i]]\ge l,lst[a[i]]\le r\)

从右到左扫描线维护单调栈,使用线段树维护区间最小值和区间最小值的个数即可。

复杂度 \(O(n\log ^2n)\)

P4063 [JXOI2017]数列

题目链接

\(f[i,L,R]\) 表示考虑前 \(i\) 个元素可以构成多少个合法的序列满足 \(a[i]\) 的前驱为 \(L\) 后继为 \(R\)

\(l\not=r\) 时,考虑 \(i\)\((L,R)\)(开区间)范围内取到几。

注意到,无论 \(a_i\) 取到 \((L,\min(r_i,R-1)]\) 内的哪个数,对应的方案数都是相同的(因为对应任意一种钦定 \(a_i\) 的方案都可以通过 “移动” \(a_i\) 调整出一种新的方案)。

那么可以考虑枚举 \(a_{i+1}\) 的取值与 \(a_i\) 的取值(\(a_i\) 只用枚举常数次)转移,转移时需要注意边界。

初始化:\(f[1,-\infty,+\infty]=r_1\)

复杂度 \(O(nr^3)\)

2022.2.18

P7560 [JOISC 2021 Day1] フードコート

题目链接

考虑将所有操作离线,扫描线扫序列维,数据结构维护时间维。

扫描线降维之后的弱化问题:

简化问题:

维护一个初始为空的队列,一共 \(n\) 个时刻,每个时刻做出如下操作之一:

  • 不进行任何操作。
  • 在队尾插入 \(k\)\(val\)
  • 从队头弹出 \(k\) 个元素,如果不足 \(k\) 个元素就把队列弹空。
  • 查询队列的第 \(k\) 个元素是几,如果不足 \(k\) 个就输出 \(0\)

如果当前扫到序列的第 \(i\) 个位置,对于每个时间作用到第 \(i\) 个位置上的操作使用序列维护,维护两个序列,一个维护所有操作的“数量影响”(插入 \(t\) 个人定义为 \(+t\),弹出 \(t\) 个人定义为 \(-t\)\(a[]\),一个维护操作的类型(“即对于插入操作维护插入的人的类型”)\(type[]\)

对于一个在时刻 \(time\) 的询问,只有发生在时刻 \(1\sim time\) 的操作会对询问产生影响。

考虑找到 \(time\) 之前最后一个时刻 \(last\),满足时刻 \(last\) 队列为空。

那么发生在 \(last\) 之后的所有形如 “pop \(k\) 个元素” 的操作,都会被完整执行,而我们只在意进行这些操作后的结果,我们可以强制所有 pop 操作在 push 操作之后执行,可以使用归纳法证明这样最后操作的结果是不变的。

那么如果我们能够找到时刻 \(last\),那么只需要在所有 push 操作构成的序列中,二分出一个位置使得 push 操作的次数 = 总的 pop 操作次数,就可以知道所有被 pop 出去的元素是哪些,进而可以求出剩下的第 \(k\) 个元素。

考虑将序列 \(a[]\) 按所有队列为空的时刻分段:

单独考虑每一段,每一段的和一定 \(\le 0\) 每段的最后一段一定是形如:\([-t,0,0,0,...,0]\) 的。

将每一段形如 \([-t,0,0,0,...,0]\) 拿掉,考虑前面一段。

前面的任意一端前缀和,一定严格大于 \(0\)(前面任意时刻,队列非空)。

所以,对于固定的一段来说,任意后缀和一定 \(\le 0\)

而对于一个队列为空的时刻 \(time\) ,一定可以看成若干这样的段的拼接,因此 \(a[1\sim time]\) 的任意后缀和一定 \(\le 0\)

并且如果 \(a[1\sim time]\) 的任意后缀和 \(\le 0\),那么在时刻 \(time\),队列一定为空。

如果时刻 \(time\) 队列不为空,考虑 \(<time\) 的所有时刻中最后一个队列为空的时刻 \(lst\)

因为时刻 \((lst,time]\) 队列非空,所以 \(a(lst,time]\) 的任意前缀和均 \(>0\)(这时 \(a(lst,time]\) 的前缀和可以看成对应时刻队列内的元素个数)。

那么这一段的和一定是 \(>0\) 的,进而就找到了一个 \(>0\) 的后缀。

因此对于时刻 \(time\) 如果 \(a[1\sim time]\) 的任意后缀和 \(\le 0\),那么时刻 \(time\) 队列一定为空。

现在可以称:时刻 \(time\) 队列为空等价于 \(a[1\sim time]\) 的任意后缀和 \(\le 0\)

接下来回到本题,考虑如何处理一个时刻 \(time\) 的询问。

考虑找出前缀 \(a[1\sim time]\) 的最靠后的最大前缀和,令这个位置为 \(pos\),那么 \(time\) 前最后一次队列为空的时刻 \(last=pos-1\)

那么使用线段树维护单点修改以及 \(a[]\) 的区间最大后缀和及其即可。

几何直观的方法:折线图

考虑使用折线图描述前缀和。

其中红色是队列为空的时刻。

那么不难发现,这次队列空了那一定得比上次空的时刻低(即考虑在空了之后的相对变化)。

那么队列最后一次空的位置就是最小前缀和取到的最靠后的位置。

而最小前缀和取到的最靠后的位置,等价于最大后缀和取到的最靠前的位置 -1(因为后缀和可以转化成整体和 - 前缀和)。

2022.2.19

P6116 [JOI 2019 Final]たのしいたのしいたのしい家庭菜園

题目链接

不要找性质找魔怔了,判断合法性可以在做完 DP 的时候判

实际上,本题只需要一个很简单的观察:

  • 在最优解中,同色的元素排列的顺序一定是与原序列中的顺序一样的。

  • 确定了最终结果的颜色序列,就一定确定了花费。

那么可以令 \(f[i,1/2/3,j,k,l]\) 表示考虑最后结果的颜色序列中的前 \(i\) 位,有恰好 \(j\)\(1\)\(k\)\(2\)\(l\)\(3\) 且第 \(i\) 位为 \(1/2/3\) 的所有序列中最小花费。

因为 \(i=j+k+l\) ,所以可以去掉一维。

预处理逆序对刷表转移即可。

复杂度 \(O(n^3)\)

Loj #3011. 「JOI 2019 Final」画展

题目链接

考虑将所有画按 \(V\) 为第一关键字,\(S\) 为第二关键字从小到大排序,所有画框按 \(C\) 从小到大排序。

那么每一个画能匹配的画框为一个后缀。

我们需要选出一种画和画框的匹配方案,使得从左到右每幅画匹配的画框大小单调递增(即匹配的画框排序后的下标单调递增)。

因为每幅画匹配的画框是一段后缀,所以考虑倒着枚举每幅画,每次匹配尽量靠后的画框。

复杂度 \(O(n\log n)\)

P6118 [JOI 2019 Final]珍しい都市

题目链接

首先,定义“点 \(t\) 对点 \(u\) 有贡献”等价于 \(t\)\(u\) 的独特的城市。

钦定点 \(u\) 为根,令点集 \(L_u\) 表示到所有到点 \(u\) 距离最远的叶子节点构成的集合,对点 \(u\) 有贡献的点一定在 \(L_u\) 中所有点到 \(u\) 的路径的交上。

注意,路径交上的所有点并不都一定对 \(u\) 有贡献。

因此一个想法就是考虑找到随便一个点 \(v\) 距离点 \(u\) 最远,考察 \(u,v\) 两点间的路径上的点。

而考虑离点 \(u\) 最远的点,可以选一条直径 \(s-t\)\(s,t\) 两个点中一定存在一个点是距离点 \(u\) 最远的点。

进而问题就转化成了:给定一个点 \(rt\),以 \(rt\) 为根,求出每个点 \(u\)\(rt\) 路径上所有对点 \(u\) 有贡献的点的颜色数。

分别以 \(s,t\)\(rt\) 求一遍上面的问题即可。

接下来考虑如何去求解上面转化后的问题。

考虑一个在点 \(u\) 到根节点路径上的点 \(p\) 不会对点 \(u\) 产生贡献的充分必要条件:存在一个点 \(t\) 使得 \(t\)\(u\) 的距离等于 \(p\)\(u\) 的距离,按照点 \(t\) 的位置分类讨论:

  • \(t\)\(u\) 子树内。

  • \(t\)\(u\) 子树外。

考虑维护出一个点集 \(T_u\)\(\forall x\in T_u\) 满足:

  • \(x\) 在根节点到 \(fa[u]\) 的路径上。

  • 不存在一个点 \(t\)\(u\) 的子树外,使得 \(dist(u,t)=dist(u,x)\)

同时考虑点集 \(S_u\)\(\forall x\in S_u\) 满足:

  • \(x\) 在根节点到 \(u\) 的路径上。

  • 不存在一个点 \(t\) ,使得 \(dist(u,t)=dist(u,x)\)

并且 \(S_u\subseteq T_u\),删掉 \(T_u\) 中所有满足存在一个点 \(t\)\(u\) 子树内,使得 \(dist(u,x)=dist(u,t)\) 的点 \(x\) 即可将 \(T_u\) “变成” \(S_u\)

考虑 \(u\) 的一个儿子 \(v\),想要构造出 \(T_v\),需要对 \(T_u\) 进行哪些 “改造”(或者说点集如何变化)。

\(v\) 的子树外等价于 \(fa[v]\) 的子树外并上 \(v\) 的兄弟子树

  • 先令 \(T_v\gets T_u\cup \{u\}\)

  • 删掉 \(T_v\) 中所有满足存在一个点 \(t\) 满足 \(t\) 属于 \(v\) 的兄弟的子树中,\(dist(u,t) = dist(u,x)\) 的点 \(x\)

而 “删掉 \(T_v\) 中所有满足存在一个点 \(t\) 满足 \(t\) 属于 \(v\) 的兄弟的子树中,\(dist(u,t) = dist(u,x)\) 的点 \(x\)”,可以转化成 “删掉 \(T_v\) 中所有 $dist(u,x) <= \text{v 的所有兄弟子树的最大深度 + 1} $ 的点 \(x\)

考虑对该树做长链剖分,令点 \(u\) 的长儿子为 \(son[u]\)\(\mathrm{maxdist(u)}\) 表示 \(u\) 子树内距离 \(u\) 距离最远的点与 \(u\) 的距离,\(ts[u]\) 表示 \(u\) 的次长儿子,\(\mathrm{len(u)}=\mathrm{maxdist(ts[u])}+1\)

注意到,对于 \(u\) 的所有非长儿子,在点集 \(T_u\cup\{u\}\) 中要删除的点集都一样。

而对于点 \(u\) 的长儿子,要删除的点集为 \(T_u\cup\{u\}\) 中所有满足 \(dist(u,x)\le \mathrm{len(u)}\) 的点 \(x\)

考虑在 DFS 的过程中维护点集 \(T_u\),在进入子树 \(u\) 前,全局维护的信息应为 \(T_u\) 的信息。

进入子树 \(u\) 后依次进行以下操作:

  • 删除当前全局维护的点集中所有满足 \(dist(u,x)\le \mathrm{len(u)}\) 的点 \(x\)

  • 在当前全局维护的点集中加入点 \(u\)

  • 递归长子树。

  • 删掉当前全局维护的点集中所有满足 \(dist(u,x)\le \mathrm{maxdist(u)}\),当前全局维护的点集为 \(S_u\),同时也是对于任意轻儿子 \(v\)\(T_v\)

  • 依次递归轻子树,其中在递归轻子树前需要将点 \(u\) 加入全局维护的点集中。

  • 如果点 \(u\) 在全局维护的点集中,删除点 \(u\)

这样操作的合法性:

在递归长子树时,在长子树内进行的 “删除操作”影响到的 \(u\) 的祖先,至多影响到 \(u\)\(\mathrm{maxdist(u)}-2\) 级祖先,而这些点在处理轻子树之前本来就需要被删除。

而在递归非长子树 \(v\) 时,只会至多影响 \(u\)\(\mathrm{maxdist(v)}-1\) 级祖先,而这些祖先一定都被删光光了,因此在处理轻子树时一定不会影响到集合中 \(u\) 的祖先。

这样,一个元素至多贡献儿子个数次总复杂的为 \(O(n)\)

2022.2.20

Loj #3153. 「JOI Open 2019」三级跳

题目链接

考虑一组合法的 \(a,b,c\) ,若存在 \(i\in(a,b)\) 满足 \(A_i\ge \min(A_a,A_b)\),那么将 \(a,b\)\(A\) 比较小的位置替换成 \(i\) 一定不会更劣。

因此我们只需要考虑所有满足 \(\max\limits_{i<k<j}(A_k)<\min(A_i,A_j)\) 的点对 \(i,j\ (i<j)\) 作为三段跳起点中的 \(a,b\)

考虑满足 \(\max\limits_{i<k<j}(A_k)<\min(A_i,A_j),i<j\) 的点对 \(i,j\),令 \(k\)\(A[i+1\sim j-1]\) 中取到最大值的位置之一,那么 \(i,j\) 一定分别是 \(k\) 左右两边第一个大于 \(A_k\) 的位置。

所以这样的点对有至多 \(O(N)\) 对,即对于每个位置 \(i\),左边第一个大于 \(A_i\) 的位置和右边第一个大于 \(A_i\) 的位置构成的点对。

可以使用单调栈在 \(O(N)\) 的时间内找到所有这样的点对。

那么接下来考虑使用扫描线 + 数据结构离线处理询问,扫描线倒着扫左端点,对于每个右端点维护一个 \(B_i\) 表示如果选它当 \(c\),最大的 \(A_a+A_b\) 的值。

每次扫到一个左端点 \(i\),加入所有点对 \((i,j)\),处理贡献相当于进行一次区间取 \(\max\) 操作,这里使用线段树维护一个区间取 \(\max\) 标记维护。

而对于询问相当于询问 \([l+2,r]\) 中的 \(\max(A_i+B_i)\),使用线段树维护区间 \(\max(A_i),\max(A_i+B_i)\) 即可,同时维护一个根到节点的最大值标记即可(标记信息不能 pushup)。

复杂度 \(O(N\log N)\)

2022.2.21

P7561 [JOISC 2021 Day2] 道路の建設案 (Road Construction)

题目链接

考虑一个弱一些的问题:求第 \(k\) 大曼哈顿距离,考虑二分一个 \(d\),对于 check 通过旋转坐标系将曼哈顿距离转化成切比雪夫距离之后做一个二维数点。

但是在这个过程中,实际上并不真的需要做二维数点,我们可以维护出所有曼哈顿距离 \(\le d\) 的点对,如果点对个数 \(\ge k\) 就直接 return:

  • 将所有点按 \(x\) 排序,按顺序扫描序列,使用 set 维护 \(x\) 坐标在 \([x_i,x_i+d]\) 范围内的点即可。

那么我们发现在这个过程中可以顺便维护所有曼哈顿距离 \(\le d\) 的点对。

复杂度 \(O((n+k)\log k\log M)\),其中 \(M\) 表示值域大小。

需要注意在二分之后,如果第 \(k\) 大曼哈顿距离是 \(d\),那么我们需要找到所有曼哈顿距离 \(<d\) 的点对(这样才能保证是一定 \(O(k)\) 对)然后在后面补若干个 \(d\)

P7563 [JOISC 2021 Day4] 最悪の記者 4 (Worst Reporter 4)

题目链接

注意到,一定存在一种最优解使得每位选手最后被调整的评分为 \(h_i(1\le i\le n)\)

将所有 \(i\to a_i\) 建边,不难发现最后是一个基环内向树的结构。

将所有环上的点找出来以环上的点为根做树形 DP,使用线段树合并优化即可。

下面重点考虑如何优化。

转移方程 1

\[f[u,i]=c[u]\times [h[u]=i]+\sum_{v\in son(u)}\max_{i\le j\le n}(f[v,j]) \]

如果只维护 \(f[u,..]\) 的线段树,在合并 \(f[u,...]\)\(f[v,...]\) 的时候如果当前合并到的节点只有一棵线段树有,很难将其转化成区间操作通过维护标记的方式维护。

因此这里考虑令:

\[g[u,i]=\max_{i\le j\le n}(f[u,j]) \]

那么:

\[f[u,i]=c[u]\times [h[u]=i]+\sum_{v\in son(u)}g[v,i] \]

我们可以通过维护儿子 \(v\)\(g[v,...]\) 的线段树,每次合并相当于线段树对应位置相加,而如果当前合并的节点只有一棵线段树有,可以直接返回有这个节点的线段树。

那么我们可以通过合并儿子维护 \(g[v,...]\) 的线段树维护出 :

\[val(u,i)=\sum_{v\in son(u)}g[v,i] \]

的线段树。

而维护 \(f[u,...]\) 的线段树相当于在维护 \(val(u)\) 的线段树上进行一个单点加的操作。

但是我们需要进一步维护出维护 \(g[u,...]\) 从而去处理父亲的 \(f[u,...]\) 的转移。

方法 1 (二分 + 维护区间加 + 区间推平):

不难发现,因为 \(g[v,...]\) 单调非增,因此 \(val(u,...)\) 也单调非增。

因此单点修改之后只会影响一段连续的位置,可以而分出这一段位置之后使用区间推平维护。

但是涉及到区间操作,合并时就需要注意如何保证复杂度,因为合并的时候如果均是大力 pushdown 标记的话,那么可能开出一整棵线段树,复杂度会变的非常重量级。

对于使用懒标记的动态开点线段树,我们可以使用 “pushdown” 去进行动态开点,每次开儿子一定会同时开两个儿子,因此一个节点要么两个儿子都在,要么两个儿子都不在。

而当前合并的两个节点,如果存在一个节点两个儿子都不在,那么这个节点区间内的所有值一定均相等,那么合并相当于给另一棵线段树对应的区间进行一个区间加操作,因此我们还需要维护一个区间加的标记。

而区间加的标记和区间推平标记一定只有一个有值,因此 pushdown 的时候并不需要考虑优先级。

这里体现了另一个技巧:带标记的线段树合并时如果存在一个点两个儿子都不在,那么可以考虑将合并转化成区间操作保证复杂度。

方法 2 (维护区间加 + 区间取 \(\max\) 标记):

注意到,单点修改之后相当于一段区间对 \(f[u,h[u]]\)\(\max\),所以考虑对区间维护一个取 \(\max\) 标记。

但是注意到,合并的时候还需要一个区间加的操作,所以还需要维护一个区间加的标记。

因此对于线段树部分还需要考虑标记下传时的优先级,这里我们令区间加标记的优先级高于取 \(\max\) 标记。

这样就可以避免二分带来的额外时间复杂度或代码复杂度。

*转移方程 2

\[f[u,i]=c[u]\times [i\ne h[u]]+\sum_{v\in son(u)}\min_{i\le j\le n}(f[v,j]) \]

实际上可以注意到,进行区间加之后其实可以配合上一个区间取 \(\min\) 的标记去维护 \(g[u,i]=\min_{i\le j\le n}(f[u,i])\) 的线段树,不过我也没写过所以不太清楚。

2022.2.22

P7565 [JOISC 2021 Day3] ビーバーの会合 2

题目链接

如果参加秘密会议的人数为奇数,那么这场会议的期待值一定为 \(1\)

因为树的所有带权重心构成一条链,对于一个点 \(u\) 令 :

\[f[u]=\sum_{i=1}^Pd(u,p_i) \]

带权重心即为 \(f[u]\) 最小的点 \(u\),对于一个重心 \(x\),考虑一个与重心相邻的点 \(y\),有 \(f[y]=f[x]+P-2\times size[v]\),因为 \(x\) 是重心,所以 \(f[y]\le f[x]\)\(y\) 是重心当且仅当 \(f[y]=f[x]\)

\[f[x]+P-2\times size[v]=f[x]\Rightarrow P=2\times size[v] \]

因为 \(P\) 是奇数,\(size[v]\) 是整数,所以一定不存在一个 \(v\) 满足 \(P=2\times size[v]\),因此重心有且仅有一个(也可以移项为 \(P-size[v]=size[v]\),可以看成断掉边 \((x,y)\) 后分裂出来的两棵树的权值和相同)。

接下来考虑如果参加秘密会议的人数为偶数,因为所有重心构成一条链,因此考虑将这条链 “拎出来”。

那么这条链上所有点都是带权重心的必要条件就是删掉这条链上的任意一条边,剩下的两棵树的子树和相等。

而删掉链上任意一条边,剩下的两棵树子树和相等等价于链两端的子树的子树和相等且中间非链端点的子树和为 \(0\)

并且我们发现如果一条链满足这样的条件,那么这条链上的所有点一定是这棵树的带权重心。

因此对于偶数,我们相当于要找到一条最长的链使得链两端的子树大小 \(\ge P\)

可以使用点分治处理,复杂度 \(O(n\log n)\)

2022.2.23

P7804 [JOI Open 2021] Financial Report

题目链接

题意等价于求 \(A\) 的一个子序列,使得这个子序列包含 \(A_n\),且子序列中相邻的元素位置距离 \(\le D\),并且从前往后破纪录元素尽量多,求破纪录元素个数。

\(f[i]\) 表示所有以 \(i\) 结尾,\(i\) 是最后一个破纪录的位置的子序列中,最多有多少个元素破纪录。

考虑枚举前一个破纪录的位置 \(j\),那么一定要存在 \(j<p_1<p_2<...<p_k<i\),满足 \(p_1-j,p_2-p_1,...,i-p_k\le D\)\(A_{p_i}< A_i,A_j<A_i\)

那么所有合法的转移点 \(j\) 一定构成了 \(A[1\sim i]\) 的一个后缀。

最远的转移点 \(pos[i]\) 等价于从位置 \(i\) 每次往前跳不超过 \(D\) 个位置且只能跳到 \(A_j< A_i\) 的位置 \(j\) 上能跳到的最远位置上。

因为 \(i\) 的所有转移点 \(j\) 满足 \(A_j<A_i\),所以考虑按权值顺序转移。

将所有 \(A_i\) 排序,按顺序点亮一个权值的位置,两个相邻的点亮的位置之间有边当且仅当两点距离 \(\le D\) ,那么假如当前点亮了所有权值 \(<A_i\) 的位置的点,我们找到点亮的点当中位置 \(i\) 的前驱,如果前驱与 \(i\) 的距离 \(>D\) 那么 \(f[i]=1\),否则 \(pos[i]\) 就是前驱所在的连通块的最靠左的点。

使用 set 维护点亮的点,并查集维护连通块,同时使用线段树维护 rmq 转移即可。

复杂度 \(O(N\log N)\)

2022.2.24

P3153 [CQOI2009]跳舞

题目链接

注意到,实际上一种跳舞的方案是否合法只在于每个男的在每首舞曲中匹配的女生的集合,而并不在意在第几首舞曲中匹配到哪个女生。

而对于一个 \(c\) 首舞曲的跳舞方案由 \(n\)\(c\) 元组表示(每个男的在每首舞曲时匹配了哪个女的)。

但是一个更好的刻画是考虑点 \(i\) 在这 \(c\) 首舞曲中匹配的所有女的构成的集合 \(S_i\),但是我们需要证明任意一种满足每个女的匹配恰好 \(c\) 次的方案都是合法的。

考虑使用网格图描述匹配,如果第 \(i\) 个男的和第 \(j\) 个女那么在网格图上就让 \(a[i,j]=1\)

那么命题等价于存在一种方案使得每次枚举一个排列 \(p\),将所有 \(a[i,p_i]\) 格子上的数减一,最终可以让网格图中每个位置都为 \(0\)(恰好做 \(c\) 次)。

其中网格上的格子满足每行有 \(c\)\(1\),每列有 \(c\)\(1\)

\(c=1\) 时显然可以。

如果 \(c=k\) 时可以,那么 \(c=k+1\) 时显然也可以,因为每轮删除会让每行的 \(1\) 的个数减少 \(1\),每列的 \(1\) 的个数减少 \(1\),那么最后就是 \(c=1\) 的情况了。

那么考虑二分 \(c\)

每次 check 考虑如下建图:

  • 将每个男的拆成两个点 \(u,u'\) 连边 \((S,u,c),(u,u',k)\)

  • 将每个女的拆成两个点 \(u,u'\) 连边 \((u,T,c),(u'u,k)\)

  • \((u,like,1),(u',dislike',1)\)

每次 check 看一下最大流是否等于 \(n\times c\) 即可。

2022.2.25

P3973 [TJOI2015]线性代数

题目链接

\[T=A*B \]

\[T_i=-C_i+\sum_{j=1}^n A_j\times B_{j,i} \]

\[T*A^T=\sum_{i=1}^nT_i\times A_i \]

\[ans=\sum_{i=1}^nA_i\times (-C_i+\sum_{j=1}^n A_j\times B_{j,i}) \]

\[-\sum_{i=1}^n A_iC_i+\sum_{i=1}^n\sum_{j=1}^nA_i\times A_j\times B_{j,i} \]

可以看成一个物品选择问题:\(n\) 件物品,选第 \(i\) 件物品的花费为 \(C_i\),同时选第 \(i\) 件物品和第 \(j\) 件物品的收益为 \(B_{j,i}+B_{i,j}\),求最大收益。

可以将所有同时选第 \(i,j\) 物品单独建一个点 \(node(i,j)\) 点的权值为 \(B_{j,i}+B_{j,i}\) ,对于每种物品也单独建点 \(p(i)\)\(node(i,j)\to p(i),node(i,j)\to p(j)\)

那么本题相当于一个最大权闭合子图问题。

另一种考虑方式。

最小割一个比较有利的性质是:从 \(S\)\(T\) 所有路径上,至少割一条边,即表示一个或的关系。

选物品 \(i\) 且选物品 \(j\) 可以获得 \(node(i,j)\) 的收益可以转化成:

  • 选物品 \(i\) 或不获得 \(node(i,j)\) 的收益。

  • 选物品 \(j\) 或不获得 \(node(i,j)\) 的收益。

因此考虑将所有物品与 \(S\) 连边,所有 \(node(i,j)\)\(T\) 连边。

割物品 \(i\) 表示选物品 \(i\),割 \(node(i,j)\) 表示不获得 \(node(i,j)\) 的收益。

那么:

形式化的:

\[\max(\sum w-\sum c)=\min(V-\sum w-\sum c) \]

其中等式左边表示选的物品获得的收益减去费用,右边表示总收益减去未获得的收益减去选的物品的费用。

P3227 [HNOI2013]切糕

题目链接

问题可以看成向一个 \(P\times Q\) 中的矩阵中填数,位置 \((i,j)\) 能填的数的范围在 \([1,R]\) 范围内,位置 \((i,j)\)\(k\) 的花费为 \(v(i,j,k)\),两个相邻的位置上填的数相差不能超过 \(D\),形式化的位置 \((x,y)\) 上填的数是 \(f(x,y)\)\((x',y')\)\((x,y)\) 相邻,那么需要满足 \(|f(x,y)-f(x',y')|\le D\)

那么考虑对于每个位置拆成 \(R\) 个点(即一条链),割掉一个点前面的边表示选择该权值。

那么接下来考虑考察 \(|f(x,y)-f(x',y')|\le D\) 的限制:

  • \(f(x,y)-D\le f(x',y')\)

  • \(f(x',y')-D\le f(x,y)\)

可以将一个位置链上的 \(i\) 向相邻的列中 \(i-D-1\) 的权值连边权为无穷的边。

那么如果一条链上割了 \(i\),那么相邻的链一定会割 \(\ge i-D\) 的位置。

2022.2.27

P3980 [NOI2008] 志愿者招募

题目链接

这是一个线性规划做法。下面举的栗子为样例。

\(X_i\) 为第 \(i\) 类志愿者的招募数,\(P_i\) 为第 \(i\) 天招募志愿者的数量,那么可以列出一些不等式

\[\begin{cases}P_1=X_1\geq 2\\P_2=X_1+X_2\geq 3\\P_3=X_3\geq 4\end{cases} \]

我们要求 \(\min(2X_1+5X_2+2X_3)\)

\(Y_i\) 为第 \(i\) 天多招募的数量,那么可以把不等式化为等式

\[\begin{cases}P_1=X_1-Y_1=2\\P_2=X_1+X_2-Y_2=3\\P_3=X_3-Y_3=4\end{cases} \]

\(P_0=0,P_4=0\),上下相邻两项相减得

\[\begin{cases}P_1-P_0=X_1-Y_1=2\\P_2-P_1=X_2+Y_1-Y_2=1\\P_3-P_2=-X_1-X_2+X_3+Y_2-Y_3=1\\P_4-P_3=-X_3+Y_3=-4\end{cases} \]

注意到每个变量恰出现 \(2\) 次且系数一正一负。

我们可以把每个等式看做一个点,正数代表流入,负数代表流出,那么等式相当于流量平衡。

因此我们得到了这样的建图方法:

  • 如果 \(P_i-P_{i-1}>0\),从 \(i\)\(T\) 连容量为 \(P_i-P_{i-1}\)、费用为 \(0\) 的边,否则从 \(S\)\(i\) 连容量为 \(P_{i-1}-P_i\)、费用为 \(0\) 的边,表示等式中的常数项。
  • \(i\)\(i+1\) 连容量为 \(+\infty\)、费用为 \(0\) 的边,表示 \(Y_i\)
  • 对于每类志愿者,从 \(t_i+1\)\(s_i\) 连容量为 \(+\infty\)、费用为 \(c_i\) 的边,表示 \(X_i\)

这样子跑最大流,得到每条边的流量作为对应变量的值,可以得到一组满足不等式的解。而我们希望 \(\sum X_i\times w_i\) 最小即整张图的总费用最小,因此求出最小费用最大流即可。

P3358 最长k可重区间集问题

题目链接

首先考虑将原问题对偶成:

  • 令集合 \(T=I-S\)

  • \(\min(\sum_{z\in T}|z|)\)

写成线性规划的形式。

首先注意到,直线 \(L\) 上的所有点中,我们只需要考察所有线段端点被覆盖的次数即可。

\(x_j\) 表示线段 \(j\) 是否在集合 \(T\) 中,\(len[j]\) 表示线段 \(j\) 的长度,\(cover(i)\) 表示所有覆盖位置 \(i\) 的线段构成的集合。

\(k_i\gets \max(0,|cover(i)|-k)\)

\[\sum_{j\in cover(i)}x_j\ge k_i \Rightarrow -y_i+\sum_{j\in cover(i)}x_j=k_i,\text{其中} 1\le i\le m \]

考虑差分。

\[-y_1+\sum_{j\in cover(1)}x_j=k_1\\ -y_i+\sum_{j\in cover(i)}x_j+y_{i-1}-\sum_{j\in cover(i-1)}x_j=k_i-k_{i-1},\text{其中} 2\le i\le m \\ y_m-\sum_{j\in cover(m)}=-k_m \]

那么这样,在约束条件中,每个 \(y_i\) 出现两次,且系数分别为 \(+1,-1\),每个 \(x_j\) 出现两次且系数分别为 \(+1,-1\),可以考虑使用最小费用最大流解决。

\[y_i\ge 0 \]

\[0\le x_j\le 1 \]

\[\min(\sum_{j=1}^n x_j\times len[j]) \]

对于 \(0\le x_j\le 1\) 的限制可以考虑使用限制边的容量以达到对变量的约束。

考虑 \(m+1\) 个关键点,编号分别为 \(1\sim m\)

因此考虑以下建图:

  • \(\forall 1\le i\le m\)\(i\)\(i+1\) 连一条容量为 \(\infty\),费用为 \(0\) 的边。

  • \(\forall 1\le i\le n\),线段 \([s[i],t[i]]\) \(t[i]+1\)\(s[i]\) 连一条容量为 \(1\),费用为 \(len[i]\) 的边。

  • 如果 \(k_i-k_{i-1}>0\),从 \(i\)\(T\) 连一条容量为 \(k_i-k_{i-1}\) 费用为 \(0\) 的边,否则从 \(S\)\(i\) 连一条容量为 \(k_{i-1}-k_i\),费用为 \(0\) 的边。

全集的答案减去最小费用最大流的费用即可。

bzoj #1283. 序列

题目链接

首先,考虑对偶:

  • \(S\) 表示所选子序列位置构成的集合。

  • \(T\gets \{1,2,3,...,n\}-S\)

  • \(\forall 1\le i\le n-m+1,\sum_{i\le j\le i+m-1}[j\in T]\ge m-k\)

  • \(\min\{\sum_{i\in T}C_i\}\)

写成线性规划的形式。

\(x_i\) 表示位置 \(i\) 是否在 \(T\) 中,其中 \(1\le i\le n,x_i\in \{0,1\}\)

约束形式可以写成:

\[\forall 1\le i\le n-m+1,\sum_{i\le j\le i+m-1}x_j\ge m-k \]

添加辅助变量 \(y_i\ge 0\) 变成等式:

\[\forall 1\le i\le n-m+1,-y_i+\sum_{i\le j\le i+m-1}x_j= m-k \]

差分:

\[-y_1+\sum_{1\le j\le m}x_j=m-k\\ \forall 2\le i\le i-m+1,-y_i+\sum_{i\le j\le i+m-1}x_j+y_{i-1}-\sum_{i-1\le j\le i+m-2}x_j= 0\\ y_{i-m+1}-\sum_{i-m+1\le j\le n}x_j=k-m \]

满足每个变量仅在两个等式左边出现,且系数分别为 \(+1,-1\),建图跑最小费用最大流即可。

考虑如下建图:

  • 建立 \(n-m+2\) 个点。

  • 如果 \(m-k>0\),连边 \((1,T,m-k,0),(S,n-m+2,m-k,0)\),否则答案为 \(\sum C_i\)

  • \(\forall 1\le i\le n-m+1\),连边 \((i,i+1,\infty,0)\)

  • \(\forall 1\le i\le n\),连边 \((\min(i+1,n-m+2),\max(1,i-m+1),1,C_i)\)

2022.2.28

CF1061E Politics

题目链接

考虑一棵树时,怎么做。

考虑对偶:

  • \(S\) 表示选择的点的集合,\(T\gets \{1,2,3,...,n\}-S\)

  • \(u\) 为根的子树中有恰好 \(size[u]-limit[u]\) 个点在集合 \(T\) 中。

  • 最小化 \(\sum_{v\in T} a[v]\)

写成线性规划的形式,令 \(x_i\) 表示点 \(i\) 是否在集合 \(T\) 内,\(x_i\in \{0,1\}\)

那么约束形如:

\[\sum_{v\in subtree(u)} x_v=size[u]-limit[u] \]

要最小化:

\[\sum_{i=1}^n x_i\times w_i \]

考虑对于所有具有约束的点建虚树,令 \(sum(u)=\sum_{v\in subtree(u)} x_v\)\(val(u)=size[u]-limit[u]\)

\(son(u)\) 表示 \(u\) 在虚树上儿子构成的点集(可能不太严谨,准确的说是所有满足向上一个关键点是 \(u\) 的所有关键点构成的集合,其中 \(u\) 也是关键点,这里定义“一个点在虚树上”等价于该点是关键点。)。

那么:

\[sum(u)-\sum_{v\in son(u)}sum(v)=val(u)-\sum_{v\in son(u)} val(v) \]

那么对于任意 \(x_i\),在等式左边出现且仅出现一次,系数为 \(+1\)

只要再构造出一个等式,使得每个 \(x_i\) 在该等式中均出现一次,系数为 \(-1\) 即可。

令根节点为 \(rt\),那么:

\[\sum_{i=1}^n x_i=val(rt)\Rightarrow-\sum_{i=1}^n x_i=-val(rt) \]

对于虚树上的点 \(u\) 定义 \(z(u)=val(u)-\sum_{v\in son(u)} val(v)\) 特别的,这里定义 \(z(0)=-val(rt)\)

因此我们就构造出了一系列的等式,满足 \(x_i\) 在等式左边出现恰好两次且系数分别为 \(+1,-1\)

考虑使用最小费用最大流处理该线性规划问题。

但是这个题并不用真的把虚树建出来,令 \(up[u]\) 表示 \(u\) 上面(包括点 \(u\) )第一个关键点即可。

定义关键点集合为 \(pos\)

如果只有一棵树,考虑如下建图:

  • 对于每个点 \(u\),建边 \((0,up[u],1,a[u])\)

  • 对于 \(u\in pos\cup\{0\}\),如果 \(z(u)<0\),建边 \((S,u,|z(u)|,0)\),如果 \(z(u)>0\),建边 \((u,T,z(u),0)\),特别的有且仅有 \(z(0)<0\)

考虑两棵树时,怎么做。

注意到,在等式组:

\[sum(u)-\sum_{v\in son(u)}sum(v)=val(u)-\sum_{v\in son(u)} val(v) \]

中,每个变量 \(x_i\) 出现恰好一次,且所有等式右边相加后的结果为 \(val(rt)\)

既然是两棵树,考虑对另一棵树中的所有等式两边乘上 \(-1\)

那么这样就构造出了一组等式满足等式左边任意一个变量出现恰好两次且系数恰好为 \(+1,-1\),等式右边所有常数和为 \(0\)(如果不为 \(0\) ,意味着两棵树根节点子树内(即整棵树)被选的点数不同,那么一定不存在一组解)。

那么同样可以使用费用流建模:

\(up_i[u]\) 表示在树 \(i\) 中, \(u\) 上面(包括点 \(u\) )第一个关键点,\(i\in \{0,1\}\)

  • 对于每个点 \(u\) ,添加边 \((up_1[u],up_0[u],1,a[u])\)

  • 对于树 \(0\) 中所有的限制点 \(u\),添加边 \((S,u,z_1(u),0)\),对于树 \(1\) 中所有限制点 \(u\),添加边 \((u,T,z_0(u),0)\)

P2153 [SDOI2009]晨跑

题目链接

因为一条边只能在一条路劲中出现,所以任意一条原图中的边可以建一天容量为 \(1\) 的边。

对于点经过至多一次的限制,将编号为 \(2\sim n-1\) 的点拆点限流即可。

CF818G Four Melodies

题目链接

对于 \(1\le i<j\le n\),如果 \(|i-j|=1\)\(i\equiv j\pmod 7\),连一条从 \(i\)\(j\) 的有向边。

那么原题等价于从该有向图中选 \(4\) 条点不相交的链使得所选的点最多。

不难得到一种朴素的流网络建图:

  • 对于序列中的位置 \(i\),建立两个点,编号分别为 \(idx[i,0],idx[i,1]\),连边 \((idx[i,0],idx[i,1],1,1)\)

  • 建立一个虚点 \(p\),连边 \((S,p,4,0)\),同时连边 \((p,idx[i,0],1,0)\) ,其中 \(1\le i\le n\)

  • 对于有向图中的一条边 \((u,v)\) 建边 \((idx[u,1],idx[v,0],1,0)\)

但是这样朴素建图边数是 \(O(n^2)\) 的。

注意到,对于模 \(7\) 同余的等价类之内的边等价于将该等价类中所有位置拿出来排序,一个位置向之后所有位置连边。

但是考虑将模 \(7\) 同余的等价类中的所有位置从小到大拉出一条链,拆点时每个点再拉一条边 \((idx[i,0],idx[i,1],\infty,0)\),表示从这个点 “经过” 但不选取。

对于两个位置上的权值相差恰好为 \(1\) 的限制,因为一个位置后面接的要么是 \(a_i+1\),要么是 \(a_i-1\),而如果我们确定了要接一个 \(a_i+1\),那么在最优解中接的一定(可以是)\(i\) 后面第一个 \(a_i+1\)\(a_i-1\) 同理(如果不是,将位置向前调一定不劣)。

因此我们只需要连一个位置的后继位置即可。

这样新的流网络建图只需要建 \(O(n)\) 条边。

P3159 [CQOI2012]交换棋子

题目链接

问题等价于将所有黑色棋子移动到指定的格子中,因为所有黑格子在指定的位置中,那么所有白色棋子也一定在指定的格子中。

因为 “交换棋子” 这种操作比较抽象,考虑转化成一个更平凡的操作。

注意到交换两个颜色相同的棋子是没意义的,而交换两个异色棋子的操作可以将操作看成每次 “移动黑色棋子”。

那么我们可以用若干条黑色棋子的移动路径去表示一个方案。

考虑使用一条 \(S\to T\) 的可行流表示一个黑色棋子的移动路径。

考虑一个黑色棋子的移动对格子参与操作的次数影响。

考虑一个黑色棋子从 \(u\) 走到 \(v\) 的路径,对于路径上除了 \(u,v\) 外的点,均会贡献两次操作次数,对于 \(u,v\) 分别贡献了一次操作次数。

因此一个棋子的移动对一个格子的影响分为三种:

  • 只进不出(终点)

  • 只出不进(起点)

  • 又出又进(不是起点也不是终点)

并且可以注意到,一个点至多是一个棋子的起点 / 终点。

因此一个点进入的次数比出去的次数 / 出去的次数比进入的次数至多多 \(1\)

因此考虑将一个点拆成三个点 \(left\to mid\to right\),如果该点是目标终点之一,那么边权分别为 \(\lceil \dfrac{w}{2} \rceil,\lfloor \dfrac{w}{2}\rfloor\),如果该起点是起点之一 那么边权分别为 \(\lfloor \dfrac{w}{2}\rfloor,\lceil \dfrac{w}{2} \rceil\),否则边权均为 \(\lfloor \dfrac{w}{2} \rfloor\),这些边的费用均为 \(0\)

感性理解一下,任意一种路径安排的方案我们都可以找到一种合适的移动顺序使得任意一个点有至多一个黑色棋子。

对于原图中移动的边直接连边(费用为 \(1\) ),同时 \(S\) 向所有初始有棋子的点的 \(mid\) 连边,目标有棋子的点的 \(mid\)\(T\) 连边即可。

posted @ 2022-02-27 21:24  Themaxmaxmax  阅读(64)  评论(0编辑  收藏  举报