<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>题解 on Zirnc's Blog</title><link>https://blog.chungzh.cn/categories/%E9%A2%98%E8%A7%A3/</link><description>Recent content in 题解 on Zirnc's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 29 Jul 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.chungzh.cn/categories/%E9%A2%98%E8%A7%A3/index.xml" rel="self" type="application/rss+xml"/><item><title>网络流题集</title><link>https://blog.chungzh.cn/oi-history/flow-sol/</link><pubDate>Sat, 29 Jul 2023 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/flow-sol/</guid><description>最大流 Luogu-P1231 教辅的组成 三倍经验： Luogu-P1402 酒店之王 / Luogu-P2891 [USACO07OPEN] Dining G
一眼丁真建图：S-&amp;gt;练习册-&amp;gt;书-&amp;gt;答案-&amp;gt;T
然而是错的。很明显，书有可能被多次匹配，与题意不符。
正确的建图：S-&amp;gt;练习册-&amp;gt;书（拆点）-&amp;gt;答案-&amp;gt;T
为什么中间层的书要拆点呢？因为一本书不能被重复选用。我们的目的是保证一本书流出的流量只能是 $1$。所以我们把每个代表书的点拆成两个点，左边的点和练习册连边，右边的点和答案连边；左右对应点之间也要连一条容量为 $1$ 的边。
Luogu-P2764 最小路径覆盖问题 定理：最小路径覆盖数=$|G|$-二分图最大匹配数
首先我们假设现在原图内每个点都是一条路径，此时最少路径数为 $n$。
考虑合并路径，当且仅当两条路径首尾相连的时候可以合并。
将点 $x$ 拆成出点 $x$ 和入点 $x+n$，当我们连接 $u, v$ 时，转化为连接 $u, v+n$。将 $S$ 与所有 $u$ 连边，将所有 $u+n$ 与 $T$ 连边。所有边的容量都为 $1$。
在一开始每个点都是一条独立的路径，每次合并将两条路径合并为一条路径，那么最终路径即为点数减去最大匹配数，这样求得的路径覆盖即为最小路径覆盖。
对于输出路径，用 to 记录下一个节点，tag 标记该节点前面是否还有点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 ll dfs(int u, int t, ll flow) { if (u == t) return flow; ll ans = 0; vis[u] = 1; for (int &amp;amp;i = cur[u]; ~i; i = e[i].</description></item><item><title>CF-559C Gerald and Giant Chess</title><link>https://blog.chungzh.cn/oi-history/cf-559c/</link><pubDate>Sun, 21 May 2023 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/cf-559c/</guid><description>CF-559C Gerald and Giant Chess / AtCoder DP-Y Grid 2
给定一个 $H*W$ 的棋盘，棋盘上只有 $N$ 个格子是黑色的，其他格子都是白色的。在棋盘左上角有一个卒，每一步可以向右或者向下移动一格，并且不能移动到黑色格子中。求这个卒从左上角移动到右下角，一共有多少种可能的路线。
$(1 ≤ h, w ≤ 105, 1 ≤ n ≤ 2000)$
$O(hw)$ 的暴力 DP 很好想，但是过不了。
假设没有障碍，从 $(1, 1)$ 到 $(i, j)$ 的方案数是 $C_{i+j-2}^{i-1}$（等于 $C_{i+j-2}^{j-1}$）。可以这么理解：可以用 $D, R$ 来表示一条路径，那么从 $(1, 1)$ 到 $(i, j)$ 的路径中有 $i-1$ 个 $D$ 和 $j-1$ 个 $R$。于是问题转化为从 $i+j-2$ 个位置中选 $i-1$ 个放 $D$ 的方案数。
如果有一个障碍，从正面统计方案数很困难，正难则反，考虑将总的方案数减去经过障碍的方案数。假设障碍的位置是 $(x, y)$，终点是 $(h, w)$，经过障碍的方案数就是 $C_{x+y-2}^{x-1} * C_{h-x+w-y}^{h-x}$（乘法原理）。</description></item><item><title>Luogu-P4755 Beautiful Pair</title><link>https://blog.chungzh.cn/oi-history/luogu-p4755/</link><pubDate>Sun, 30 Apr 2023 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/luogu-p4755/</guid><description>Luogu-P4755 Beautiful Pair
题意 小 D 有个数列 ${a}$，当一个数对 $(i,j)$（$i \le j$）满足 $a_i$ 和 $a_j$ 的积不大于 $a_i, a_{i+1}, \ldots, a_j$ 中的最大值时，小 D 认为这个数对是美丽的。请你求出美丽的数对的数量。
$1\le n\le{10}^5$，$1\le a_i\le{10}^9$。
编程时的问题 对 ST 表不熟悉！ 更 zz 的是，对 lower_bound 和 upper_bound 理解有问题，来复习一下小学知识：lower_bound 是找到“大于等于”的位置，upper_bound 是“大于”。写这道题的时候找小于某数的位置莫名其妙地用了 lower_bound，更没有 -1，完全是随手写的，半天也没察觉到这里有问题。 综上，我是 zz。
思路 考虑分治（据说这是套路），我们找出一个区间 $[l, r]$ 内的最大值位置 $mid$，然后统计所有跨过 $mid$ 的答案，再递归处理 $[l, mid-1], [mid+1, r]$。假设 $mid$ 左边的数是 $a_i$，右边的数是 $a_j$，根据题目得 $a_i * a_j \le a_{mid}$，即 $a_j \le \lfloor\frac{a_{mid}}{a_i}\rfloor$。那么我们枚举 $a_i$，然后用主席树统计右区间内小于 $\lfloor\frac{a_{mid}}{a_i}\rfloor$ 的数的个数。</description></item><item><title>ABC209F Deforestation</title><link>https://blog.chungzh.cn/oi-history/abc-209f/</link><pubDate>Fri, 28 Apr 2023 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/abc-209f/</guid><description>ABC209F Deforestation
题意：给出 $n$ 棵树的高度，砍第 $i$ 棵树的花费是 $h_i+h_{i-1}+h_{i+1}$，求有多少种方案能使得砍完所有树的总代价最小。
砍一棵树的代价只与相邻的树高度有关。下面研究砍 $h_i$ 与 $h_{i+1}$ 的先后顺序对答案的影响。
先砍 $h_i$ 后砍 $h_{i+1}$：$h_i+h_{i-1}+h_{i+1}+h_{i+1}+h_{i+2}$ 先砍 $h_{i+1}$ 后砍 $h_i$：$h_{i+1}+h_i+h_{i+2}+h_i+h_{i-1}$ 作差后得到：$h_{i+1}-h_i$。当 $h_{i+1}&amp;gt;h_i$ 时，应该先砍 $h_{i+1}$。当 $h_{i+1}&amp;lt;h_i$ 时，应该先砍 $h_i$。因此，对于相邻的两棵树，先砍高的那棵最优。
插入 DP（insertion DP）：先考虑排好前 $i-1$ 个数，再往中间插入第 $i$ 个数。
令 $\mathit{f}_{i,j}$ 表示排好了前 $i$ 棵树的砍树次序，且第 $i$ 棵树排在第 $j$ 位，得到最小代价的方案数。
当 $h_{i+1} &amp;gt; h_i$ 时，应先砍 $i+1$，那么 $\mathit{f}{i+1,j} = \sum{k=j}^{i}\mathit{f}_{i,k}$
当 $h_i &amp;gt; h_{i+1}$ 时，应先砍 $i$，那么 $\mathit{f}{i+1,j} = \sum{k=1}^{j-1}\mathit{f}_{i,k}$
当 $h_i = h_{i+1}$ 时，砍哪棵都可以，$\mathit{f}{i+1,j} = \sum{k=1}^i\mathit{f}_{i,k}$</description></item><item><title>ABC133F Colorful Tree</title><link>https://blog.chungzh.cn/oi-history/abc-133f/</link><pubDate>Fri, 14 Apr 2023 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/abc-133f/</guid><description>F - Colorful Tree
题意 有一个 $N$ 个节点的树，每条边有颜色、边权。
您需要处理 $Q$ 个询问，每个询问给出 $x_i,y_i,u_i,v_i$，您需要求出假定所有颜色为 $x_i$ 的边边权全部变成 $y_i$ 后，$u_i$ 和 $v_i$ 之间的距离。询问之间互相独立。
分析 DFS 序的思想套上主席树，root[i] 的权值线段树存从根到 $i$ 结点的每种颜色的边数（$cnt$），以及该颜色的长度和（$sum$）。顺便记录从根到 $i$ 结点的距离。利用差分，$dis(i, j) = dis(root, i)+dis(root, j)-2dis(root, LCA(i, j)$。然后 $i, j$ 的路径中该颜色的长度和也用同样的方法求出。那么答案就是 $dis(i, j) - \text{该颜色的长度和} + \text{该颜色的边数}*y$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include &amp;lt;bits/stdc++.</description></item><item><title>CSP-J/S2022 题解与反思</title><link>https://blog.chungzh.cn/oi-history/csp2022-sol/</link><pubDate>Sat, 05 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/csp2022-sol/</guid><description>学校 OI 停（tui yi）了，周末有空的时候补补。
J T1 乘方 Luogu-P8813 [CSP-J 2022] 乘方
如果 $a^b$ 的值不超过 ${10}^9$，则输出 $a^b$ 的值，否则输出 -1。数据范围：$1 \le a, b \le {10}^9$。
$2^{30}=1073741824 &amp;gt; 10^9$，所以循环最多 29 次就能判断是否超过 $10^9$。注意 $1$ 的任何次幂都是 $1$，不能进行循环，特判一下即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include &amp;lt;bits/stdc++.h&amp;gt;using namespace std; const long long MAXX = 1e9; int main() { long long a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b; if (a == 1) { cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; endl; } else { long long s = 1; bool flag = 0; for (long long i = 1; i &amp;lt;= b &amp;amp;&amp;amp; s*a &amp;lt;= MAXX; i++) { s *= a; if (i == b) { flag = 1; } } if (!</description></item><item><title>ARC101B Median of Medians - 中位数</title><link>https://blog.chungzh.cn/oi-history/arc-101b/</link><pubDate>Sun, 23 Oct 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/arc-101b/</guid><description>D - Median of Medians
题意 给定一个整数序列 $a[1],a[2],&amp;hellip;.a[n]$，那么对于 $a$ 序列的任意一个连续子序列 $a[L],a[L+1],&amp;hellip;&amp;hellip;a[R]$，其中 $1&amp;lt;=L&amp;lt;=R&amp;lt;=n$, 求出该连续子序列的中位数，记为 $b[L][R]$。
显然 $b$ 数组共有 $n*(n+1)/2$ 个整数。
输出 $b$ 数组的中位数。
分析 关于中位数有一个 Trick：
我们二分一个数 $mid$，对于原序列中 $\ge mid$ 的数，我们标记为 $1$；反之，对于 $&amp;lt; mid$ 的数，我们标记为 $−1$。 标记结束后，如果一个区间内的标记和大于等于 $0$，说明中位数大于等于 $mid$，那么向右二分；反之向左。 对于本题，我们对 $b$ 数组二分它的中位数 $mid$，并按 $mid$ 对 $a$ 数组进行 $+1,-1$ 标记。然后问题就变为了：统计有多少个区间的标记和 $\ge 0$。
记这个区间数为 $cnt$，若 $cnt\ge \lfloor \frac{n(n+1)/2+1}{2} \rfloor$，说明 $b$ 数组实际中位数 $\ge mid$，向右二分。否则向左二分。
怎么求有多少个区间的标记和 $\ge 0$ 呢？我们可以做一个前缀和 $s$，统计 $i &amp;lt; j$ 且 $s[i] \le s[j]$ 的个数。这是一个二维偏序问题，可以搭配树状数组解决。</description></item><item><title>CF-342E Xenia and Tree - 根号分治</title><link>https://blog.chungzh.cn/oi-history/cf-342e/</link><pubDate>Thu, 06 Oct 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/cf-342e/</guid><description>CF342E Xenia and Tree
题意 给定一棵 $n$ 个节点的树，初始时 1 号节点为红色，其余为蓝色。
要求支持如下操作：
将一个节点变为红色。 询问节点 $u$ 到最近红色节点的距离。 共 $q$ 次操作。
$1 \le n, q \le 10 ^5$
分析 首先我们有两种暴力思路：
每次将一个点变为红色，就从那个点开始 BFS，更新它周边结点的最小值，直到无法更新。 每次询问，都和之前的红色点求 LCA，计算出距离，再取最小值。 这两种做法都过不了。但我们可以将它们结合起来，这就是根号分治（a.k.a. 操作分块）。
我们把操作序列以 $\sqrt m$ 为块长分块，对于一个询问，有两种情况：
在同一块内且在询问之前的修改，可以暴力 LCA 求距离。 对于之前块的修改，可以在处理完那个块之后，从块中修改的红点开始多源 BFS 更新每个点的答案。 最后答案便是两种情况取最小值。
大概也许是 $O((n+m)\sqrt m)$？其实我不会算，但是挺快的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 #include &amp;lt;bits/stdc++.</description></item><item><title>CF-1385E Directing Edges</title><link>https://blog.chungzh.cn/oi-history/cf-1385e/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/cf-1385e/</guid><description>CF-1385E Directing Edges
题意 给定一个由有向边与无向边组成的图，现在需要你把所有的无向边变成有向边，使得形成的图中没有环。
如果可以做到请输出该图，否则直接输出&amp;quot;NO&amp;quot;。
分析 我们先只连接有向边，然后做一遍拓扑排序，如果失败了，就说明有环，输出 “NO”。
然后处理剩下的无向边。对于无向边 $(u, v)$，如果 $u$ 的拓扑序小于 $v$，那么令这条边的方向是 $u\rightarrow v$。否则，方向就是 $v\rightarrow u$。因为这条边是从拓扑序小的点指向拓扑序大的点，所以必然不会形成环。
RECORD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 #include &amp;lt;algorithm&amp;gt;#include &amp;lt;cstdio&amp;gt;#include &amp;lt;cstring&amp;gt;#include &amp;lt;iostream&amp;gt;#include &amp;lt;vector&amp;gt; using namespace std; const int MAXN = 200005; int n, m; vector&amp;lt;int&amp;gt; G[MAXN]; int c[MAXN], topo[MAXN], id[MAXN], t, bn, x[MAXN], y[MAXN]; bool dfs(int u) { c[u] = -1; for (auto v : G[u]) { if (c[v] &amp;lt; 0) return false; else if (c[v] == 0 &amp;amp;&amp;amp; !</description></item><item><title>Luogu-P3521 「POI2011」ROT-Tree Rotations</title><link>https://blog.chungzh.cn/oi-history/luogu-p3521/</link><pubDate>Sun, 14 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/luogu-p3521/</guid><description>题意 给定一颗有 $n$ 个叶节点的二叉树。每个叶节点都有一个权值 $p_i$（注意，根不是叶节点），所有叶节点的权值构成了一个 $1 \sim n$ 的排列。
对于这棵二叉树的任何一个结点，保证其要么是叶节点，要么左右两个孩子都存在。
现在你可以任选一些节点，交换这些节点的左右子树。
在最终的树上，按照先序遍历遍历整棵树并依次写下遇到的叶结点的权值构成一个长度为 $n$ 的排列，你需要最小化这个排列的逆序对数。
$2 \leq n \leq 2 \times 10^5$， $0 \leq x \leq n$，所有叶节点的权值是一个 $1 \sim n$ 的排列。
分析 按照先序遍历整棵树，取叶结点，用人话说就是从左到右取叶子结点。
重要性质：交换了一个点的左右子树之后，不会影响左子树内和右子树内的逆序对数量。
考虑一个任意的结点，对它的子树中叶子的逆序对进行分类讨论：
都在左子树内； 都在右子树内； 跨越左右子树。 交换左右子树之后，受到影响的显然只有第三种情况。第一、第二种情况分治下去就可以转化成第三种再计算。
如何计算答案呢？一开始，对于每一个叶子结点，我们都建立一棵权值线段树（动态开点）并记录 $p_i$ 出现了 $1$ 次。合并 $r1, r2$ 时，逆序对的个数就是 $tree[rc[r1]] \times tree[lc[r2]]$。因为 $r1, r2$ 对应的权值区间 $[L, R]$ 是相同的，而 $lc[r1], lc[r2]$ 对应的权值区间就是 $[L, M]$， $rc[r1], rc[r2]$ 对应的权值区间是 $[M+1, R]$，$rc[]$ 中记录的数都比 $lc[]$ 中的要大，而 $r1$ 对应的数的编号小于 $r2$（也就是 $r1$ 是左子树，$r2$ 是右子树），满足逆序对的条件。</description></item><item><title>Luogu-P1776 宝物筛选</title><link>https://blog.chungzh.cn/oi-history/luogu-p1776/</link><pubDate>Fri, 12 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/luogu-p1776/</guid><description>Luogu-P1776 宝物筛选
题意 终于，破解了千年的难题。小 FF 找到了王室的宝物室，里面堆满了无数价值连城的宝物。
这下小 FF 可发财了，嘎嘎。但是这里的宝物实在是太多了，小 FF 的采集车似乎装不下那么多宝物。看来小 FF 只能含泪舍弃其中的一部分宝物了。
小 FF 对洞穴里的宝物进行了整理，他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值，之后开始了宝物筛选工作：小 FF 有一个最大载重为 $W$ 的采集车，洞穴里总共有 $n$ 种宝物，每种宝物的价值为 $v_i$，重量为 $w_i$，每种宝物有 $m_i$ 件。小 FF 希望在采集车不超载的前提下，选择一些宝物装进采集车，使得它们的价值和最大。
对于 $100%$ 的数据，$n\leq \sum m_i \leq 10^5$，$0\le W\leq 4\times 10^4$，$1\leq n\le 100$。
解法 1：二进制优化 每一个数都可以表示成 $2$ 的幂的和（因为每一个数都可以用二进制表示）。
时间复杂度：$O(nW\sum \log m_i)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include &amp;lt;bits/stdc++.</description></item><item><title>Luogu-P2254 「NOI2005」瑰丽华尔兹</title><link>https://blog.chungzh.cn/oi-history/luogu-p2254/</link><pubDate>Fri, 12 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/luogu-p2254/</guid><description>「NOI2005」瑰丽华尔兹
题意 不妨认为舞厅是一个 $N$ 行 $M$ 列的矩阵，矩阵中的某些方格上堆放了一些家具，其他的则是空地。钢琴可以在空地上滑动，但不能撞上家具或滑出舞厅，否则会损坏钢琴和家具，引来难缠的船长。每个时刻，钢琴都会随着船体倾斜的方向向相邻的方格滑动一格，相邻的方格可以是向东、向西、向南或向北的。而艾米丽可以选择施魔法或不施魔法：如果不施魔法，则钢琴会滑动；如果施魔法，则钢琴会原地不动。
艾米丽是个天使，她知道每段时间的船体的倾斜情况。她想使钢琴在舞厅里滑行的路程尽量长，这样 1900 会非常高兴，同时也有利于治疗托尼的晕船。但艾米丽还太小，不会算，所以希望你能帮助她。
$100%$ 的数据中，$1\leq N, M \leq 200$，$K \leq 200$，$T\leq 40000$。
分析 首先我们定义一下状态。设 $dp[t][i][j]$ 表示 t 时刻，在 $(i, j)$ 滑行的最长路程长度。状态转移方程是 $dp[t][i][j] = \max(dp[t-1][i][j], dp[t-1][i^{&amp;rsquo;}][j^{&amp;rsquo;}])$，$i^{&amp;rsquo;}$ 和 $j^{&amp;rsquo;}$ 是合法的走过来的位置，取决于 $t$ 时刻船体倾斜的方向。
这样设计状态的话，时间复杂度为 $O(TNM)$，空间似乎也是问题。
这时候我们发现还有一个变量 $K$ 没有用到，考虑把状态设为 $dp[t][i][j]$ 表示在第 $t$ 时间段内，在 $(i, j)$ 滑行的最长路程长度。时间复杂度为 $O(KN^3)$，暂时还不行。
我们看看能不能进一步优化。下面假设当前船体倾斜的方向是东。设当前时间段长度是 $tim$，上一个时间段钢琴的位置在 $(i, m)$，那么 $dp[t][i][j] = \max_{j-m&amp;lt;=tim}{dp[t-1][i][m]+j-m}$。在这个式子中，只有 $m$ 一个变量，并且 $j-m&amp;lt;=tim$，合法决策在一段相邻区间内，可以用到单调队列优化！
对于两个决策 $m_1 &amp;lt; m_2$，$m_2$ 优于 $m_1$ 时仅当：
$$ \begin{aligned} dp[t-1][i][m_1]+(j-m_1) &amp;amp; &amp;lt; dp[t-1][i][m_2]+(j-m_2) \\ dp[t-1][i][m+1]+m_2-m_1 &amp;amp; &amp;lt; dp[t-1][i][m_2] \end{aligned} $$</description></item></channel></rss>