不杂题不选做,Week1
带 * 的指未完工的,带 % 的指期望写却没写的。
Day1
CF643G Choosing Ads
占 \(p\%\) 的数,摩尔投票法。
当全局时,我们一般是记录 \(k\) 个候选数及其“净次数”,若一个数在里面时,次数 +1,否则若有空位置就放进去,放不下就全体次数 -1。
它的本质是一直选 \(k+1\) 个两两不同的数删去,答案一定在剩下的数当中。
对于区间上的问题,用一棵线段树维护,每个节点上维护上面所说的类似的东西(\(k\) 个候选数及其还剩下的个数),暴力维护的时间复杂度是 \(\mathcal O\left(k^2\right)\),可以接受。
%CF1365G Secure Password
可以想到一种接近的做法:询问对于某一位是 0 的或和与某一位是 1 的按位或和,然后对于的 \(P_i\),它就是对于 \(i\) 的每一位,拿相反的对应集合或起来。这样需要 \(20\) 个集合,不够好。
这个题目中要求的 \(13\) 究竟是什么呢?考虑 \(13\) 是最小的满足 \(\binom{x}{[x/2]}\ge n\) 的最小的 \(x\)(而 \(\binom{12}{6}=924<n\))。我们可以尝试从组合数的角度思考集合的构造。
我们可以继续将二进制用起来,具体而言我们使用所有的满足 \(0\le x<2^{13}\) 且 \(\mathrm{popcount}(x)=6\) 的 \(x\),并对每个位置 \(i\) 附一个值 \(m_i\),就像上文“接近的做法”中的直接的二进制那样。
接下来,对于每个二进制位,将 \(m_i\) 对应位上为 \(1\) 的位置 \(i\) 的值作为一个集合,这样刚好 \(13\) 个集合 \(S_i\)。
查询时,对于某个 \(i\),找到所有 \(m_i\) 二进制下第 \(j\) 位为 \(0\) 的 \(j\),求 \(S_j\) 的或和。为什么这是对的呢?因为除了 \(m_i\) 外,其余的一定在某个 \(m_i\) 为 \(0\) 的位上为 \(1\),而这是建立在所有 \(m_i\) 的 popcount 相等的基础上的。
P2619 [国家集训队] Tree I
无法再经典的 wqs 二分题。
什么是 wqs 二分?能用它解决的题(也许)满足如下性质:
- 元素间有一定的限制
- 强制选 \(k\) 个元素
- 元素带权,且要使权值和取到最值
- 当没有选 \(k\) 个元素的限制时会很容易解决
- 选指定元素时的最优解画出函数来是个凸包
这题的凸性好证吗?不知道。但可以对着网上的证明跑一遍。
文章1(tree.pdf) 文章2
定理一:所有最小生成树中的可能的白边数量构成一个区间 \([l,r]\)。
证明:考虑 Kruskal 的连边过程,唯一的使最小生成树不唯一的因素是有相同权值的边。但不论这些相同权值的边的处理顺序如何调换,在处理完这些边后图的连通关系是相同的。也就是说,我们可以对于所有具有相同权值的边,将它们的顺序任意调换,每一小段构成一个区间,于是整体也构成一个区间。
定理二:记 \(G(x)\) 为将所有白边的权值加上 \(x\) 得到的图,\(w(G,T)\) 为 \(G\) 中 \(T\) 的边权和,那么若 \(G(x)\) 的最小生成树 \(T\) 中恰好有 \(a\) 条白边,那么这棵生成树就是有 \(a\) 条白边的最小生成树的一个最优解。
证明:考虑反证法,若存在 \(T'\) 比 \(T\) 更优,则 \(w(G(0),T')<w(G(0),T)\),那么直接有 \(w(G(a),T')<w(G(a),T)\),与 \(T\) 的定义矛盾。
定理三:设 \(G(x)\) 中最小生成树的可能白边数量构成的区间为 \([l_x,r_x]\),则有 \(r_x=l_{x-1}\)。
证明:依然考虑 Kruskal 的选边过程,将边按边权均为 \(x\) 和颜色相同的划分为集合 \(B_x,W_x\)。那么若记 \(F(S)\) 表示按照 \(S\) 这个有序集从左到右地考察边所最终选择的边集,则对于 \(r_x\) 会优先选白边,按序选出 \(W_1',B_1',\dots,W_x',B_x'\) 这样的边集,其中 \(W_x'\subseteq W_x,B_x'\subseteq B_x\);对于 \(l_{x-1}\) 而言,由于白边的权值减了 \(1\),优先级增加了,则相当于是 \(W_0',B_1',W_1',\dots,W_{x-1}',B_x'\),其中 \(W_0',W_1',\dots\) 与上文的 \(W_1',W_2',\dots\) 是完全一致的。因此 \(r_x=l_{x-1}\)。
由此可知 \(r_x\) 呈现出一种单调不增的关系,仅需二分 \(r_x\) 即可由定理二计算出答案。这种东西现在被广泛地称作“带权二分”。
等等,我的凸性呢?其实是有的,考虑在上面的定义下真正的最小生成树的权值和怎么算,其实就是加上了 \(r_x\times x\)。当 \(x\) 单增时 \(r_x\) 单调不增,这就形成了一个凸包啊。
接下来真正从凸包的方式看看 wqs 二分。(以上凸壳为例)
文章1  文章2
对于一个特定斜率 \(c\) 的直线,找到刚好与凸包相切的位置,则此时它与 \(y\) 轴的截距也是所有还在凸包上的特定斜率直线中最大的。如上面文章中的图所示:

在图中,当直线恰好经过绿色的点时,它与 \(y\) 轴的截距最大。
注意我们现在其实是不知道凸包上每个点的具体位置的(否则还要二分干啥??),但是我们通过证明可以知道它确实形成了一个凸包。
那么这个截距有什么实际意义呢?将绿色的点的坐标记作 \((k,F(k))\),则截距可以表示为 \(F(k)-k\times c\)。这相当于是对于所有关键物品,都额外少了 \(c\) 的价值。
因此,可以说我们只需要把所有关键物品的权值全部减去 \(c\),就可以通过跑一个没有限制的算法得到最大的截距,以及得到最大截距时选择的关键物品个数,然后就可以反推答案。
至于凸包上包含 \((k,F(k))\) 的相邻的几个点斜率相等的情况,此时截距相同,这可以看作是多选择一个物品,但是价值为零。因此只需要每次求出最大的 \(k_{max}\),并判断它与我们所需求的 \(k\) 的大小关系。
对了,对于本题一般的写法,时间复杂度是 \(\mathcal O(m\log m\log V)\),但是实际上由于我们只对所有白边的权值统一进行平移,白边的顺序和黑边的顺序本身没有改变,因此可以事先排好序,在二分中仅仅是做归并,这样时间复杂度可以优化为 \(\mathcal O(m(\log m+\log v))\)。
P4983 忘情
首先一段的权值为 \((sum+1)^2\)。
这样的话,假设对于一段 \(x+y\) 的段分成 \(x,y\) 两段(均指 \(sum\)),则权值减少了 \(2xy-1\)。显然分开的越多,可选的 \(2xy-1\) 就会越来越小,但永远是正的。因此它其实是单调的,并且也属于下凸壳(但这是不严谨的)。
有关本题凸性的严谨证法是它满足四边形不等式。
那么这就可以套一个 wqs 二分,把它变成没有限制时的问题了。注意我们要同时求出最小值(因为是下凸壳)和取得最小值时最大的关键物品个数(这里是段数)。而这是经典的斜率优化问题。
怎么斜率优化来着?
令 \(S_i\) 表示 \(x_i\) 的前缀和,\(f_i\) 表示将 \(i\) 左侧处理完毕后的最小值,则有
这是非常自然的 \(\mathcal O(n^2)\) 做法。
接下来把它转化为 \(y=kx+b\) 的形式,其中 \(y\) 是只关于 \(j\) 的,\(kx\) 是同时关于 \(i,j\) 的,\(b\) 是只关于 \(i\) 的项。因此有
每次在队列中维护这些直线所构成的凸包就可以做到单次 \(\mathcal O(n)\),总体是 \(\mathcal O(n\log n)\) 的。
注意现在 wqs 二分的增量增在每段的权值上,以及在斜率一致时选段数最多的转移。
P5308 [COCI 2018/2019 #4] Akvizna
还是分段题,只不过现在一段 \((j,i]\) 的贡献变为了 \(\frac{i-j}{n-j}\),初始有 \(f_0=0\),求 \(f_n\)。
分成恰好 \(k\) 段依然是 wqs 二分。
至于证明,将 \((j,i]\) 分为 \((j,k]+(k,i]\ (j<k<i)\),则贡献的增量为
整体是大于零的,并且当分的段越多时,\(i,j,k\) 的差值是越来越小的,因此上式会小得更慢。
因此它是单调的,也可以看作是一个上凸壳。
接下来是后面那个 DP 怎么做。
依然考虑斜率优化。最后推出式子
然后就没了。细节和上面那题是类似的。
CF958E2 Guard Duty (medium)
排序是第一步。然后可以比较直接地想到一段区间肯定是不会跨越别的时间的,不然又占空间代价又大,非常不好。于是对于没有 \(k\) 的限制的情况,有 \(f_i=\max(f_{i-1},f_{i-2}+a_i-a_{i-1})\)。然后再套一个 wqs 二分即可,增量在区间上。
凸性证明在郭羽冲《浅谈函数的凸性在 OI 中的应用》中有提到,借助了费用流模型:
- S 向奇数位置连一条容量为 1,费用为 0 的边;
- 偶数位置向 T 连一条容量为 1,费用为 0 的边;
- 每个奇数位置 \(i\) 向 \(i-1\) 和 \(i+1\)(如果存在)连一条容量为 \(+\infty\),费用分别为 \(a_i-a_{i-1}\) 和 \(a_{i+1}-a_i\) 的边。
这个图流量恰好为 \(m\) 时的最小费用即为答案,而费用流的最小费用关于流量是下凸的,由此凸性得证。这也是为什么本题可以用“模拟费用流”及“反悔贪心”做,因为费用流的做法并不复杂,而且可以优化。
P5633 最小度限制生成树
其实做法是很板的,基本不需要说。不过是当边权一致时优先选择与 \(s\) 相连。然而必须用上面提到的归并优化时间复杂度。凸性证明可见 题解,或见下面从 文章 中截来的文字:

%CF739E Gosha is hunting
本题可用 文章1 或 文章2 的方式解决。
一般的遇到多点共线且欲求 \(F(k)\) 的 \(k\) 不在端点上的情况时采用钦定极值的做法的写法对于高维 wqs 二分来讲由于 \(k,l\) 间有关因而不能直接对 \(k\) 做特殊化处理而不管 \(l\) 是无法胜任的。因此可以做切线与 \(x=k\) 的交点,设其为 \(G(x)\),则它与 \(F(x)\) 的凸性恰好相反,且极值为 \(F(k)\)。当 \(F(x)\) 上凸时,\(G_k(x)=kx+\max_y(F(x)-xy)\)。此时可以三分求 \(G_k(x)\) 的最值。
我们姑且称它为“wqs 三分”。那么本题就可以用套两次的“wqs 三分”解决这个问题。
Day2
P3515 [POI 2011] Lightning Conductor
四边形不等式:\(w(a,c)+w(b,d)\le w(a,d)+w(b,c)\)(包含不如相交)。
决策单调性:设 dp 状态为 \(S\),使 \(w(i,j)\) 取到最值的 \(j\) 记作 \(\mathrm{opt}(i)\)。那么决策单调性指 \(\forall i,j\in S,i<j\Longrightarrow\mathrm{opt}(i)\le\mathrm{opt}(j)\)。
区间包含单调性:\(\forall l\le l'\le r'\le r,f(l',r')\le f(l,r)\)。
一些性质:
- \(w(l+l,r)\le w(l,r)\) 且 \(w(l,r-1)\le w(l,r)\) 可归纳证明区间包含单调性。
- \(w(l+1,r)+w(l,r−1)\le w(l,r)+w(l+1,r−1)\) 可归纳证明四边形不等式。
- 若 \(w(l,r)=f(r)-g(l)\),则 \(w(l,r)\) 满足四边形不等式。
- 若 \(f(x)\) 为下凸函数,\(w(l,r)\) 满足区间包含单调性和四边形不等式,则有:
- \(f(w(l,r))\) 满足四边形不等式。
- 若 \(f(x)\) 单调不降,则 \(f(w(l,r))\) 还满足区间包含单调性。
 
其实还有一个有趣的点在于四边形不等式与小范围的其它 dp 并不冲突,比如当区间 \([l,r]\) 长度不超过 \(k\) 时 \(w(l,r)\) 不满足四边形不等式,超过时又满足,此时可以直接对于前一种暴力转移,后一种进行优化。
对于 1D-1D 型的 DP,若 \(w(l,r)\) 满足四边形不等式,则如下两种形式的 DP 满足决策单调性:
第一种的证明:使用反证法,假设存在 \(i<j\) 有 \(\mathrm{opt}(i)>\mathrm{opt}(j)\),那么 \(\mathrm{opt}(j)<\mathrm{opt}(i)<i<j\)。则根据四边形不等式有 \(w(\mathrm{opt}(j),i)+w(\mathrm{opt}(i),j)\le w(\mathrm{opt}(j),j)+w(\mathrm{opt}(i),i)\),两个非最优的决策点的值之和竟比最优的小,产生矛盾。第二种是类似的,多了个 \(f_j\) 罢了,最后能抵消。
做这两种都分别有一种好方法:分治和二分队列。
对于第一种的分治法,考虑仅需知道 \(\mathrm{opt}(i)\) 即可计算 \(f_i\),那么对于当前做到 \([l,r]\) 中的情况,先暴力计算出 \(mid=\frac{l+r}{2}\) 的最优决策点 \(\mathrm{opt}(mid)\),那么有 \(\forall i<mid,\mathrm{opt}(i)\le k\) 以及 \(\forall i>mid,\mathrm{opt}(i)\ge k\),递归处理。这样就好做了,时间复杂度 \(\mathcal O(n\log n)\)。
至于本题,考虑求的是 \(p_i\),移项得
将绝对值拆开,则若将 \(-\sqrt{i-j}\) 和 \(a_i-a_j\) 分别看作函数 \(w(j,i)\),则它们都满足四边形不等式,因此它们的和也满足四边形不等式。由此可解。注意 \(w\) 中传参的顺序,以及最终答案的计算方法(一正一反)。
然后对于第二种的二分队列,它主要解决的是“在线”(后面的 \(f_i\) 需要前面的 \(f_j\) 才能计算)的问题。它实际上可以用多一个 \(\log\) 的时间复杂度被 cdq 分治套上面的那个分治替代,相当于在线转离线。
但是我们需要学习真正的二分队列。
考虑由于 \(\mathrm{opt}(i)\) 随 \(i\) 的增加单调不降,满足 \(\mathrm{opt}(i)=j\) 的 \(i\) 构成了一段区间。由此用一个单调队列维护二元组 \(\left<[l_j,r_j],j\right>\),其中 \([l_j,r_j]\) 是目前所有满足 \(\mathrm{opt}(i)=j\) 的 \(i\) 所构成的区间,然后按照 \(l_j\) 升序排序。“目前”意味着以后的东西要做修改,而现在它们默认是当前最优的。
初始时队列中仅有 \(\left<[1,n],1\right>\)(有时是 \(\left<[1,n],0\right>\) 等等,取决于长度为 \(1\) 的区间的贡献是否为 \(0\)),然后枚举 \(i\),尝试放进队列。先将队头 \(r_j<i\) 的决策弹掉,得到 \(\mathrm{opt}(i)\),从而得到 \(f_i\)。接下来若队尾 \(\left<[l,n],p\right>\) 中 \(k\) 去决策 \(l\) 比 \(p\) 优秀,那这整个区间都应该属于 \(k\)。一直做上面的操作直到队列为空或是有交集。若队列为空,那么直接加入 \(\left<[i+1,n],i\right>\),否则就在 \([l,n]\) 中去二分出它们的决策分界点,再加入决策 \(i\)。
这样的时间复杂度是均摊 \(\mathcal O(n\log n)\) 的。可以近似把它看成有一个板子。
但是面对一些特殊的题目,这种“决策分界点”是可以直接计算的,从而省去二分的复杂度,达到优秀的线性。本题就有这样的做法,来自 Alex_Wei。
*LOJ6039 「雅礼集训 2017 Day5」珠宝
对于背包题,要时刻记住背包的复杂度如果不是某些值域特别小,是完全不可能优化的,否则就可以去冲图灵奖了。
但是这题的 \(C_i\) 就是很小。
可以设 \(f_{i,j}\) 表示考虑了 \(C\le i\) 的所有物品,一共花费 \(j\) 元的最大价值。这样的话,当我们把 \(C=i\) 的物品单独按照价值排序,则转移时选择的一定是从大到小的那些物品。
P4767 [IOI 2000] 邮局 加强版
首先可以直接得到一个 dp:设 \(f_{i,j}\) 表示前 \(i\) 个村庄中放置 \(j\) 个邮局,前 \(i\) 个村庄到最近邮局的距离总和的最小值。那么转移时相当于在 \([l,r]\) 中放一个邮局,这个放中间就行。设其为 \(w(l,r)\),则转移为 \(f_{i,j}=\underset{k<i}{\min}\left(f_{k,j-1}+w(k+1,i)\right)\)。可以通过前缀和加速 \(w(l,r)\) 做到 \(\mathcal O(V^2P)\) 的时间复杂度。
由于 \(w(l,r)\) 满足四边形不等式(证明见题解),于是它是 2D-1D dp 的优化,满足 \(\mathrm{opt}(i,j)\in[\mathrm{opt}(i,j-1),\mathrm{opt}(i+1,j)]\)。在此基础上枚举即可,时间复杂度 \(\mathcal O(VP)\)。注意状态枚举的顺序,先是第二维的,然后第一维要倒着枚举,要迎合 \(\mathrm{opt}(i,j)\) 的限制。
本题由于恰好选 \(P\) 个邮局,并且实际上有单调性,所以可以进一步用 wqs 二分优化,参见 P6246 [IOI 2000] 邮局 加强版 加强版。事实上,对于这种问题均有 \(f_{i,j}\) 是关于 \(j\) 的下凸函数,因此大多都可以用 wqs 二分。
在此之外还有一种区间 dp 型的优化,即 \(f_{l,r}=w(l,r)+\underset{l\le k<r}{\min}f_{l,k}+f_{k+1,r}\),它也满足 \(\mathrm{opt}(l,r)\in\left[\mathrm{opt}(l,r-1),\mathrm{opt}(l+1,r)\right]\) 和四边形不等式。且若 \(w(l,r),f_{l,r}\) 均非负,则 \(f_{l,r}\) 满足区间包含单调性。例如 P1880 [NOI1995] 石子合并 这题就可以这么做。
CF868F Yet Another Minimization Problem
依然是先搞出一个朴素的 dp,形如 \(f_{i,j}=\underset{k<i}{\min}\left(f_{k,j-1}+w(k+1,i)\right)\)。此处这里的 \(w(i,j)\) 为 \([l,r]\) 中的相同元素对数,混乱邪恶。但是你会发现它是真的满足四边形不等式,证明如下:
对于 \([l,r](1< l\le r< n)\), \(w(l-1,r)+w(l,r+1)\) 为 \(2w(l,r)\) 加上了 \(a_{l-1}\) 和 \(a_{r+1}\) 在 \([l,r]\) 中的出现次数,而 \(w(l,r)+w(l-1,r+1)\) 为 \(2w(l,r)\) 加上了 \(a_{l-1}\) 在 \([l,r+1]\) 中的出现次数和 \(a_{r+1}\) 在 \([l-1,r]\) 中的出现次数,用人话说就是若 \(a_{l-1}=a_{r+1}\),则它们相等;否则后者会比前者大 \(1\)。于是 \(w(l-1,r)+w(l,r+1)\le w(l,r)+w(l-1,r+1)\),满足四边形不等式。
那么怎么去求 \(w(i,j)\) 呢?你会发现直接求它很难,但是如果我们使用在莫队中也被使用的双指针的话,它是可以 \(\mathcal O(1)\) 地去“移动”区间的。所以我们可以思考一种方法,使移动区间的次数是可以被接受的。我们考虑对于每一层(\(f_{i,?}\))做分治,由于分治中扫描可能的 \(\mathrm{opt}(mid)\) 是非常契合我们的这个双指针的,所以对于单层,这样的复杂度还是 \(\mathcal O(n\log n)\) 的。但是注意最好不要既扫描和递归的方向相反,这样会使常数乘二,但是时间复杂度不变。
P5574 [CmdOI2019] 任务分配问题
和上题类似,顺序对用树状数组维护,多个 \(\log\)。注意加入或删除一个元素对顺序对的贡献,以及左侧的操作和右侧的操作是不同的。
然后 这里 有一个很有趣的东西,可能以后会看看彭思进《决策单调性与四边形不等式》。
感觉这种“满足某些条件的对数”都满足四边形不等式啊,它相当于是多考虑了 \(a_{l-1}\) 在最左侧,\(a_{r+1}\) 在最右侧的对数,但是这个对“某些条件”的规定必须一致,而与 \([l,r]\) 的选取无关。比如这题就属于这种,但 CF1603D Artistic Partition 就不是这样的,所以证明起来会更加复杂。
P1912 [NOI2009] 诗人小G
来真正地写一次二分队列。
\([l,r]\) 的代价为 \(\left(|sum+r-l-L|\right)^P\),这种高次的真不好证决策单调性,只好感受一下。对于答案可能大于 \(10^{18}\) 的情况,用 long double 存储即可,但不能在计算时就与 \(10^{18}\) 取最小值,否则决策点将无法比较。注意由于要输出方案,所以要多记录下来 \(\mathrm{opt}(i)\)。
CF1279F New Year and Handle Change
显然所有操作都去替换为 \(0\) 或替换为 \(1\) 更好。不妨设要替换成 \(1\)。接下来证明凸性。证明 及下面的图片来自 pajenegod。
考虑直接以定义证明凸性,即 \(F(i+1)\ge \frac{F(k)+F(k+2)}{2}\)。
考虑做出 \(F(k)\) 与 \(F(k+2)\) 所对应的一种最优方案:

接下来把有交的线段对连线:

由于每段的长度相同,有且仅有两个连通块中下面的段比上面的多一个。这样,对于 \(F(k+1)\) 的构造,考虑将其中一个连通块翻转,然后选更优的那个:

这样的话凸性就一目了然了。然后便是比较容易的 wqs 二分。
Day3
P6569 [NOI Online #3 提高组] 魔法值
设 \(F_i\) 表示第 \(i\) 天的魔法值形成的 \(1\times n\) 矩阵,\(E\) 表示邻接矩阵,则若规定矩阵乘法:\(C_{i,j}=\underset{k}{\bigoplus}A_{i,k}B_{k,j}\),有 \(F_i=F_{i-1}\times E\)。
这种矩阵乘法对于像 \(E\) 这样的 01 矩阵的结合性是有保证的,因为它就相当于在模 \(2\) 运算下进行加法和乘法。因此它可以做矩阵快速幂。
然后便简单了,若每次询问都搞个矩阵快速幂,时间复杂度是 \(\mathcal O\left(n^3q\log a\right)\),可以通过倍增做到 \(\mathcal O\left(\left(n^3+n^2q\right)\log a\right)\)。注意开 unsigned int 或 long long。
CF750E New Year and Old Subsequence
对于 \(q=1\) 的情况,先直接设一个 \(\mathcal O(n^2)\) 的 dp:\(f_{i,j}(1\le i\le n,0\le j\le 4)\) 表示在前 \(i\) 个字符中,存在子序列是 \(\texttt{2017}\) 的前 \(j\) 位,且不存在子序列是其前 \(j+1\) 位(如果存在)或是 \(\texttt{2016}\),所需删除字符的最小值。考虑每个状态的转移:
然后可以发现 \(f_i\) 的递推仅与 \(f_{i-1}\) 有关,将上面的转移写进 \((\min,+)\) 矩阵然后上一棵线段树就行了。
这种题可以联想 P6373 「StOI-1」IOI计数,每次询问一个区间内是否存在一个特定的长度为 \(k\) 的子串,可以通过维护每个子串做到 \(\mathcal O\left(nk^2\log n\right)\)。但是这题只能做到 \(\mathcal O\left(nk^3\log n\right)\),不过可以拆矩阵减常数,不过那都是后话了。
[NOIP 2018 提高组] 保卫王国
这个东西很显然是带修树上最小权覆盖集,转成全局减去最大权独立集后,可以用 ddp 做。这是 P4719 【模板】动态 DP。
但是由于最后强制选/不选的也要计入贡献,因此此时加正/负无穷比赋值为它们好。
*P11928 [PA 2025] 子序列 / Podciągi
https://www.luogu.com.cn/problem/P11928
又是子序列题。这题求出现次数不小于 \(2\),一看就很困难,不如用所有本质不同子序列数减去只出现一次的子序列数。接下来分别看看做法。
Day4
P5056 【模板】插头 DP
这种题一般都是对于一个网格图等等长相规则且可以轻易设计状态的图,在上面做一些有关连通性的计数(如哈密顿回路,简单路径等)。主要想法是按照从上到下、从左往右枚举每个格子,维护轮廓线上每个位置的状态,哈希进一个数,然后做转移。状态的设计自然是 \(dp_{pos,state}\)。
考虑轮廓线上一个回路一定是一进一出,记左侧那个为进,那么它形似一个括号序列(因为回路向括号匹配一样不能交叉,这是全体平面图的性质),可以压缩成三进制,然而四进制会更快。这样的话,理论上来说,轮廓线状态种类数为 \(\mathcal O\left(3^{n}\right)\),但是实际上是远远达不到的,所以应该沿用 P4363 [九省联考 2018] 一双木棋 chess 的想法,把所有可能可行的状态计算出来。
然后对于每个格子,最终也一定是一进一出,所以有 \({4\choose2}=6\) 种可能的状态,并非多。对于本题,一共有八种情况,分类讨论即可。注意什么时候会对答案有贡献。
P3272 [SCOI2011] 地板
这回不用考虑那种可能隔得很远的那种连通性了,但是要维护转弯的次数,所以记一个插头的状态 \(0,1,2\) 分别为没有,未转弯,已转弯。然后一个格子有十个状态。写过上题的话这题并不难想。
感受到了哈希表的魅力啊。
P3822 [NOI2017] 整数
首先如果 \(a\ge 0\) 的话那暴力均摊下来就直接是对的了,这是非常经典的二进制累加器。问题就在 \(a<0\) 的时候,相当于加补码,要修改的位太多。
使用 文章1 中提及的 Trygub 数。它是每位的取值范围为 \((-b,b)\),而非传统意义上的 \([0,b)\)。形式话的说,就是 \(x\) 的表示方法为 \(x=\sum_i a_ib^i\),其中 \(a_i\in(-b,b)\)。进位的话就是遇 \(b\) 进一,遇 \(-b\) 进负一。这样的话整个数的正负可以仅通过最高非零位看出来,进位依然有仅与上一位相关的性质。每一位的真实值也仅与上一个非零位的负值有关,因此用一个数据结构(比如 map)去维护所有非零位,然后暴力进位,二分查询真实值。这样的时间复杂度是 \(\mathcal O(n\log n\log V)\),其中 \(V\)  是加减数的大小,并且 \(\log V\) 的底数实际上是 \(b\),所以是好的。但这样还难以过本题。
文章2 给出了一种优化的方案:注意到复杂度瓶颈在修改,修改时在 map 中访问的位置是连续的,可以使用迭代器自增的形式做到均摊一个 \(\log\),不过会带些常数。除此之外,还可以用压位等减少常数。
注意压位时容易爆 int 甚至 long long,要小心。
%CF1817E Half-sum
记 \((a,b)\) 为对 \(a,b\) 做一次合并,然后留下 \(\frac{a+b}{2}\)。
首先感觉一下,最后留下来的更大的值一定是前 \(k\) 大数搞出来的,更小的值一定是剩下 \(n-k\) 个数搞出来的。
接下来手玩可以得到对于 \((((a,b),c),d)\) 这样的一系列合并,最后的结果相当于是 \(\frac{a+b+2c+4d}{8}\)。可以发现,如果 \(a,b,c,d\) 不是单调不增的,那么可以通过邻项交换说明一定不会比单调不增得到的值小。合出最大值同理。
用数学语言说,最终的方案一定形如
此时对于 \(k\),式子为
对于所有 \(k\in[1,n)\),求上面式子的最大值。
那么你可以自然地想到正着倒着分别扫一遍,然后计算差的最大值。但是这样做最大的问题是精度不够,而高精度又太慢。即便这一切都做出来了,比大小还是很困难,使用 CF464E The Classic Problem 的主席树比大小也会被卡。此时尝试使用上题提到的 Trygub 数。
对于像动态维护差值这种有增有减的问题,使用 Trygub 数是很好的。
对于 \(k<l\),上述式子的差值一定只与区间 \([k-1,l+1]\) 有关,此时可以想到分治,也就是说对于 \([l,r]\) 的最大值求解,先求出 \(\left[l,\left\lfloor\frac{l+r}{2}\right\rfloor\right]\) 与 \(\left[\left\lfloor\frac{l+r}{2}\right\rfloor+1,r\right]\) 的最大值,再用 Trygub 数计算它们的差值是否大于等于 \(0\),这就能做这道题了。
*CF125E MST Company
wqs 二分板子,但是要输出方案。
最困难的肯定是共线时,设二分斜率的那条直线与凸包上横坐标在区间 \([l,r]\) 中的点,这意味着当 \(k\in[l,r]\) 时都有对应的生成树。
回想一下最小生成树的性质:可以对相等边权的边任意排序,最终选的条数相同,并且前面几轮合在一起的连通性一致。
Day5
P6302 [NOI2019] 回家路线 加强版
自己想只会 70pts,想不到 \(y_j=x_i\land q_j\le p_i\) 怎么做。。
首先可以想到一个朴素的 dp,状态是 \(f_{u,t}\) 表示下车时在 \(u\) 点,此时过去 \(t\) 个时刻的最小烦躁值(不含到达时刻)。但是这么做太冗余了,可以直接设 \(f_i\) 表示刚下第 \(i\) 辆列车的最小烦躁值(不含到达时刻),这其中其实蕴含着两个状态。最后的答案自然就是 \(\underset{y_i=n}{\min}\left(f_i+q_i\right)\)。暴力转移是 \(\mathcal O\left(m^2\right)\) 的(止步于此)。为了方便可以多加一个在 \(0\) 时刻到达 \(1\) 号节点的列车。
可以感受到这个转移是很像斜率优化的:
至此,一锤......还没完。
最困难的就是限制 \(y_j=x_i\land q_j\le p_i\)。
仅对于前者的话,考虑维护 \(n\) 个凸包,当 \(f_i\) 计算完毕后就放进第 \(y_i\) 个点对应的凸包。
对于后者,将其变成一个更为宽松的限制 \(p_j<p_i\),先将其排序。但是由于斜率优化必须要 \(k,x\) 均单增,所以光这样做是不行的。此时需要将上面的方法加以改进:处理完 \(f_i\) 后不急于将它放进凸包中,而是放进按 \(q_i\) 升序排序的小根堆中,枚举起始时间 \(P\) 时将 \(q_i\le P\) 的 \(i\) 放进单调队列。这样可以做到两边均单增。注意计算斜率时,横坐标可能相同,所以用乘法计算更好,但是此时要加个取等。
具体实现时由于值域较小,可以将堆用 vector 代替,精细实现时间复杂度是 \(\mathcal O(m+t)\) 的。
P9479 [NOI2023] 桂花树
这题就比较聪明智慧了。
感觉可知第一个条件是在说 \(T'\) 是在 \(T\) 的边上或点上接点接出来的,或者说 \(T'\) 中编号在 \([1,n]\) 间的点构成的虚树为 \(T\)。然后 \(m\le 1\) 就秒了,因为这和第二个条件没有任何关系,答案自然是点数加上边数,即 \(2n-1\)。
这样的话,对于 \(k=0\) 的点,可以发现加入一个点后,点数和边数都加了 \(1\),并且又变成了 \(m=1\) 的情况,所以答案应是 \(\underset{i=n}{\overset{n+m-1}{\prod}}(2i-1)\)。再加上 \(m=2\) 的一点 case,你就可以获得高贵的 70pts 了。
接下来考虑第二个条件在说什么,实际上是 \(T'\) 中前 \(i\) 个点构成的虚树中不存在编号大于 \(i+k\) 的点。也就是说,此时可以直接将一条“边”接进一条边,且某个 \([i+1,i+k]\) 的点是 \(i\) 的父亲。那这个 \([i+1,i+k]\) 由于我们考虑的 \(i\) 是从小到大加入的,是不能直接决定的。
那就把它放在那里吧!这样,我们得到了一个“空点”,可以以后再选一个数填进去。于是有了一个状压 dp,即设 \(dp_{i,S}\) 表示尝试放入第 \(i\) 个点,此时 \([i+1,i+k]\) 中遗留的空点的点集为 \(S\) 的方案数。放入第 \(i\) 个节点时,树的大小为 \(n'=n+i-1+|S|\),那么有如下的转移:
- 将 \(i\) 像 \(k=0\) 中的一样接在一条边或一个点上,则 \(S\) 除了平移一下之外没有变化,权值为 \(2n'-1\);
- 将一条“边”接进一条边,增加一个空点,\(S\) 中增加 \(i+k\),权值为边数,即 \(n'-1\);
- 将 \(i\) 填入一个空点,\(S\) 中删去一点。
最终填入 \(m\) 个点,且空点必须全部填完,故答案为 \(f_{m,\mathbb\emptyset}\)。此时终于可以发现答案和 \(T\) 的形态,甚至是点数丝毫没有关系,这是很有趣的地方。单组数据的时间复杂度为 \(\mathcal O\left(mk2^k\right)\)。有一点卡常。
Day6
【模板】最小割树(Gomory-Hu Tree)
先声明一下,原论文中真正的 Gomory-Hu 树是很难做的,现在 OI 界流行的等价流树,使用 Gusfield 算法,无法获得最小割的具体方案,但写起来简单得多。它们都是难以证明的,详细的证明可见王文涛《浅谈无向图最小割问题的一些算法及应用》。
反正这种东西,知道流程就行了吧。
不会有魔改的应用了吧。
不会吧。
会的吧。
也许在别的地方还能用 posi-modular 的性质吧。
反正这种东西,知道证明也没啥吧。
最难证的就是 Gomory-Hu 树的存在性。但若证明了一个构造出它的算法的正确性,也就变相地说明了它的存在。接下来不妨先默认它存在。事实上,不仅存在,一张图可能会有多棵 Gomory-Hu 树。Gusfield 相较于 Gomory-Hu 不必缩点,但是失去了 Gomory-Hu 树更特殊的形态。
但是这里其实并未写 Gomory-Hu 的存在性证明。
证明来自上面的那篇论文及 课件。
记一个将 \(a,b\) 割开的最小割 \(W\) 中,全体点 \(V\) 被分成两部分 \((W,V\setminus W)\),\(a\in W,b\in V\setminus W\),所有 \(uv\in E,u\in W,v\in V\setminus W\) 的 \(uv\) 构成割集 \(\alpha(a,b)\) ,其权值和为 \(\lambda(a,b)\)。若 \(W\) 仅是 \(a,b\) 的一个割的话,记 \(\delta(W)\) 为割集,权值和为 \(c(W)\)。图默认是简单无向图。
定理一:对于任意三个不同的点 \(a,b,c\),\(\lambda(a,b)\ge \min(\lambda(a,c),\lambda(c,b))\)。
证明:

由此可直接得到引理一:对于任意 \(k\) 个不同的点 \(a,b,\cdots,o,p\),有 \(\lambda(a,p)\ge\min(\lambda(a,b),\cdots,\lambda(o,p))\)。
接下来是一点定义。
对于一个集合 \(V\),若对于一个关于 \(V\) 的子集 \(U\) 的一元函数 \(f\),有 \(\forall A,B\in V,f(A)+f(B)\ge f(a\cup B)+f(a\cap B)\),则称 \(f\) 是一个子模函数;若满足 \(f(A)+f(B)\ge f(a\setminus B)+f(B\setminus A)\),则称 \(f\) 是一个反模函数。若 \(f(U)=f(V\setminus U)\),则 \(f\) 是一个对称函数。
定理二:割的权函数 \(c(U)\) 是子模函数,是对称函数,也是反模函数。
证明:对于子模函数的证明,对着韦恩图列式子。这里跳过。对称函数也是显然的。可以证明若一个函数既是子模函数又是对称函数,则它是反模函数:
由此可证。
定理三:对于一个 \(a,b\) 的最小割 \(W\),其中 \(a\in W\),以及 \(c,d\in W\),存在一个 \(c,d\) 的最小割 \(X\) 使得 \(X\subseteq W\)。
证明:令 \(Y\) 是一个 \(c,d\) 的最小割,它与 \(W\) 与 \(V\setminus W\) 均有交。可以发现 \(W\setminus Y\) 与 \(W\cap Y\) 均是在 \(W\) 中的。不妨设 \(a\in Y\),接下来说明不论 \(b\) 是否属于 \(Y\),\(W\setminus Y\) 与 \(W\cap Y\) 中都会存在一个权值不超过 \(Y\) 的,又由 \(Y\) 的假设得证。
- 对于 \(r\in Y\),首先 \(c(W)+c(Y)\ge c(W\setminus Y)+c(Y\setminus W)\),又由于 \(c(Y\setminus W)\ge c(W)\) 得 \(c(W\setminus Y)\le c(Y)\)。
- 对于 \(r\notin Y\),可以通过 \(c(W)+c(Y)\ge c(W\cup Y)+c(W\cap Y)\) 得到 \(c(W\cap Y)\le c(Y)\)。
定理三说明了不同层的最小割可以不交叉,这是证明 Gomory-Hu 树存在的一个重要定理。
由于不用会 Gomory-Hu 树的构造,就不继续写了。
Gusfield 算法的流程是对于一个点集,在其中任选两个点作为源汇点在原图上跑一边最小割,在这两点间连一条边权为最小割权值的边,然后把点集分成两部分分治求解。这样我们需要跑的最小割次数从 \(\mathcal O\left(n^2\right)\) 减少到了 \(n-1\)。
然后当询问两点间最小割时,就相当于询问我们构建的等价流树上两点间的最小边权,这个可以随便求解,反正求解等价流树的时间复杂度为 \(\mathcal O\left(n^3m\right)\),算是较高的。
p.s. 有博客中是这么写的:
这大致是不对的(没找到对应的论文),大概率是把最小割树和 Stoer-Wagner(全局最小割)弄混了。
CF343E Pumping Stations
把最小割树建出来后就和最小割完全没有关系了。。最小割树真神奇。
相当于是给定一棵有 \(n\) 个点的树,构造一个长度为 \(n\) 的排列 \(a\),使得 \(\underset{1\le i<n}{\sum}\mathrm{minedge}\left(a_i,a_{i+1}\right)\) 最大,其中 \(\mathrm{minedge}(i,j)\) 表示树上 \(i,j\) 间的路径中最小的边权。
那有一个想法是尽量少走边权最小的那条边。那么这种想法把树划分为了两个子树,也就形成了两个子问题,并且边权最小的那条边仅经过一次。这告诉我们最大收益实际上就是最小割树上的所有边权之和。方案可以类似地递归求出。
但是有没有更好的答案求法?就是说,如果这棵树不是最小割树,而是输入的一棵 \(n\le 10^5\) 的树,怎么做呢?
有一个做法是从任意一个点开始 bfs,每次把到 bfs 树上的父亲的边权最大的点拿出来,用一个优先队列维护。这么做就是为了使每条边都发挥作用。这样构造方案的时间复杂度是 \(\mathcal O(n\log n)\) 的,很优啊!
CF848D Shake It!
最小割为 \(m\) 这个性质非常神奇,先把它转成从 \(s\) 到 \(t\) 的边不交的路径条数恰好为 \(m\)。然后就做不了了。
那就从文中的操作入手,看看最小割有什么性质。
不难发现 \(G'\) 是个广义串并联图(其实是个双端串并联图,这已经非常想告诉我们接下来的做法了)。然后就运用广义串并联图方法:
- 删一度点:不存在这样的情况。
- 抹二度点:\(w_e=\min\left(w_{e_1},w_{e_2}\right)\)
- 叠合重边:\(w_e=w_{e_1}+w_{e_2}\)
然后你会想到把这种操作把原图划分为若干个并联的部分,每部分都是两个子图以一种串联的形式合在一起,组成了类似的结构。这启发我们用 dp 做这个题,比如 \(f_{i,j}\) 表示做了 \(i\) 次操作,最大流为 \(j\) 的本质不同图个数。初始时自然是 \(f_{0,1}=1\)。
接下来可以想到每次将两个子图构成的串联图并联进大图中,但是这样会算重,原因是并联是无序的,而向上面这样做其实是蕴含了串联图之间的顺序的。那有什么办法呢?答案是将多个这样的串联图插入进原图中。这样的话,可以每次将 \(t\) 个 \((a,b)\) 和 \((c,d)\) 形成的串联图作为一个并联放进 \((i,j)\),状态转移方程为
其中 \(F(a,b)\) 指在 \(a\) 个物品中任选 \(b\) 个(可重复)的方案数,即 \(\binom{a+b-1}{b}\)。
但是枚举四个也太不好了,考虑先将单个 \((a,b)\) 和 \((c,d)\) 构成的串联图预处理成 \(g_{a+c+1,\min(b,d)}\),然后再去计算 \(f\),然后又反过来预处理 \(g\),不断循环。这样的时间复杂度是 \(\mathcal O\left(n^4\log n\right)\) 的,因为可以将 \(F(a,b)\) 预处理,以及 \(t\) 的枚举本质上是个调和级数。
这转移还是不好写,主要是边界情况的 \(m\le n+1\) 以及转移不重复。
Day7
CF1349C Orac and Game of Life
整个过程一定是大的连通块把单个格子“吞并”,就是同时翻动的不断变大,直到 \(\mathcal O(n+m)\) 个时刻后所有格子同时翻转。所以预处理出每个格子被“吞并”的时刻就好。注意有一个例外是黑白交错,此时整个局面不变。
没啥好说的。注意开 long long。
P4003 无限之环
比较神秘的网络流题。
首先网格图上匹配什么的容易想到  P4474 王者之剑 那样黑白染色转成二分图。好的,转化过后每个格子有四个“插头”。
接下来对于“操作次数最小”,可以想到最小费用最大流,将现在的插头加一条边让它“掰过去”。有如下建图方法:

这也就说明了为什么题目强调直线型水管不能旋转:网络流无法处理“一条边流了另一条边必须流”的情况,而转动一次直线型水管需要同时流两条边,因此网络流做不动。相比之下,插头 dp 虽然无法处理本题这样的数据范围,在它眼中直线型水管和别的水管却是一样的。
至于为什么边上的点需要拆开,而不拆开会错,考虑两个 T 型水管相对的情况,无法保证边只用一次。
为了使代码短一些,可以将上面三种需要加额外边的格子分别旋转到一个指定的状态,记录旋转的次数。至少不会写三百行(
P4553 80人环游世界
来学习上下界网络流了。
上下界网络流就是每条边 \(e\) 有个流量下界 \(f_e\) 和流量上界 \(g_e\),要使它真正流过的流量 \(f\) 满足 \(f\in[f_e,g_e]\)。
对于无源汇上下界可行流,不妨假设开始时每条边 \(e\) 都流了 \(f_e\) 的流量,那么此时这条边的容量便成了 \(g_e-f_e\),初始流量为 \(0\)。但是这样做完每个点的流量不一定平衡,即流入量不一定等于流出量,记 \(u\) 点的流入量为 \(in_u\),流出量为 \(out_u\)。那么我们尝试在这基础上构建一个网络流,使得可以补偿流入量或是流出量。
具体地,建一个源点 \(S\) 和汇点 \(T\),若一个点 \(u\) 当前的 \(in_u\ge out_u\),即需要多向外流出 \(in_u-out_u\) 的流量,则建立一条 \(S\) 到 \(u\) 且流量为 \(in_u-out_u\) 的边;对于 \(in_u<out_u\) 的情况,建立一条 \(u\) 到 \(T\) 且流量为 \(out_u-in_u\) 的边。由此,若新图跑满(\(S\) 连出去的边全部满流)时,全图的流量才能平衡。
除了给边上限制,还可以给点上限制。具体做法和上面所说的一模一样。
有源汇上下界可行流可以直接加一条汇点到源点且流量为 \(\infty\) 的边,转化为无源汇上下界可行流。
对于有源汇上下界最大流,可以先找到一个可行流,然后在删去附加边后的残量网络上再跑一次从 \(S\) 到 \(T\) 的最大流,将可行流流量和最大流流量相加即可。
最小流也是类似地,相当于退流,在删去附加边后的残量网络上跑一遍从 \(T\) 到 \(S\) 的最大流,然后将可行流流量减去最大流流量即可。
回到这道题,自然可以对城市拆点,然后用上下界限制每个城市必须走的人数(就做完了),但是还有“不用上下界”的做法。
为了方便,记 \(u\underset{cost}{\xrightarrow{[l,r]}}v\) 表示一条 \(u\) 到 \(v\),流量在 \([l,r]\) 间,费用为 \(c\) 的边,我们将其拆成 \(S\underset{0}{\xrightarrow{[0,l]}}v,u\underset{cost}{\xrightarrow{[0,r-l]}}v,u\underset{cost}{\xrightarrow{[0,l]}}T\)。考虑这样做的正确性,就是一种另类的强制满流,这是有源汇上下界最小费用可行流的一种写法。对于最大流,需要在残量网络上再跑一遍最小费用最大流,然后加起来。
这道题就是一道有源汇上下界最小费用可行流的模板题,照上面写就行。其实由于这题的上下界相同,所以可行流就是最大流。由于上下界相同,也可以用 \(cost=-\infty\) 达到强制满流,只不过这不通用。

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号