2023.12 ~ 谨纪念那些 为登山事业献出生命的探险家
1. P9746 「KDOI-06-S」合并序列
- 首先合并是区间合并所以要区间 dp,从前缀,后缀,以及中间夹着的某一段转移而来。
- 枚举后缀,这个时候问题相当于询问 \([l',r]\) 内是否存在
xxxoooxxxooo
这样的选择情况,两段x
都是合法区间,并且 xor 和为 \(v\)。 - 值域与定义域互换,现在考虑对每个 \(l,v\) 求出最小的 \(g(l,v)=r\) 使得 \([l,r]\) 存在那种情况即可,然后同样需要一个 \(h(l,v)\) 表示最小的 \(r\) 存在
oooxxxx
这种情况。 - 注意需要按照 \(l\) 从大往小转移,轻微卡常。
2. P9747 「KDOI-06-S」签到题
一个区间合法的充要条件是存在 \(x\) 满足其为区间按位或,并且《\(x\) 左侧所有数或起来》《\(x\) 右侧所有数或起来》二者有其一为 \(x\)。
扫描线扫右端点,不同的按位或将左端点分为 \(\log A\) 个区间,对于每个区间 \([l,r]\) 先在区间按位或 \(v\) 在序列中存在位置的 vector 中二分,找到 \([l,r]\) 内最靠后的 \(a_x=v\)。
再找到最右侧的 \(p\) 满足 \([p,x-1]\) 的按位或为 \(a_x\),最左侧的 \(q\) 满足 \([x+1,q]\) 的按位或为 \(a_x\)。
- 如果 \(q\leq r\),此时左端点在 \([l,x]\) 内的左端点均合法。
- 否则,如果 \(p\geq l\) 此时左端点在\([l,p]\) 内的左端点均合法。
现在对每个右端点有 \(\log A\) 个合法的左端点区间,每次询问一个区间的最长的合法子区间。再次按照询问的右端点扫描线,用两棵线段树支持一下区间 chkmax 单点查询就行。
时间复杂度是 \(\mathcal{O}(n\log n\log A)\)。
3. P9055 [集训队互测 2021] 数列重排
贪心,首先考虑 \(< k\) 那些,想让每个区间都合法,那么就考虑先把 \(a=1\) 的排出来,之后每一个块都是先 \(a=0\) 的再 \(a=1\) 的,也就是34 01234 01234...
这样子。
然后考虑往里面插入 \(\geq k\) 的那些,一定是插在两边或者两组之间的空里面(如果 \(a\) 并不是全 1 那么将 3401234
看成同一组)
正难则反,先假设所有 \(\geq k\) 的区间都合法。然后写出每个空里面需要减去的代价关于球数的式子,是二次函数,凸的。所以可以每次贪心选最优的放。这个时候再看两侧的空每次放球的代价是 1,2,3,....
,而中间的空每次放球的代价是 k,k+1,k+2,...
。所以先往两侧放 \(2(k-1)\) 个球然后剩余所有位置挨个轮着放就行。
4. P8984 [北大集训 2021] 末日魔法少女计划
构造 \(k\) 区间合并结构。\(n,k\) 比较小,所以可以仿照 Sqrt Tree 的构造来把最优的划分 dp 出来。设 \(f_k(n)\) 表示长度为 \(n\) 的序列每个区间都能最多 \(k\) 次合并的最小步数。分成若干块,此时每个块内部需要满足所有区间都能 \(k\) 次合并出;头尾的块需要可以 \(1\) 次出后/前缀;中间的块需要 \(1\) 次合并出前缀或后缀;把中间的块看成元素,整块之间需要 \(k-2\) 次合并出所有区间。
那么先枚举两头的块长,中间的之和剩余长度有关可以用另外一个 dp 算:
\(f_{k,1}=f_{k-1}(n)+n-1\) 可以 \(1\) 次合并出前缀且 \(k\) 次合并出所有区间。
\(f_{k,2}=f_{k-2}(n)+2n-3\) 可以 \(1\) 次合并出前缀,\(1\) 次合并出后缀且 \(k\) 次合并出所有区间。
再根据记录的最优决策点构造。
5. 无向带权图全局最小割
随机化做法,定义 \(C(G)\) 为将 \(G\) 按边权不断随机边缩起来,直到缩了 \(\frac{n}{\sqrt{2}}\) 次得到的图(每次缩边之后去重边)。定义函数 \(F(G)\) 表示求 \(G\) 的全局最小割,将 \(G_1,G_2\) 为两次随机算出来的 \(C(G)\),将 \(F(G_1)\) 和 \(F(G_2)\) 取较小值作为答案。
随机取边可以按度数(邻边权值和)随机点,在按照边权随机邻边。再进行 \(\mathcal{O}(n)\) 的合并。那么 \(C(G)\) 的复杂度是 \(\mathcal{O}(n^2)\),整个做法的复杂度是 \(T(n)=2T(\frac{n}{\sqrt 2})+\mathcal{O}(n^2)=\mathcal{O}(n^2\log n)\)。
现在来分析概率,考虑一次缩边缩的是最小割的边的概率。假设最小割权值是 \(c\),那么最小度数 \(\geq c\),总边权 \(\geq nc/2\),选中最小割中的边的概率 \(\leq \frac{2}{n}\)。所以缩 \(m\) 次没缩到最小割的概率是 \(\frac{n-2}{n}\frac{n-3}{n-1}...\frac{n-m}{n-m+2}\frac{n-m-1}{n-m+1}=\frac{(n-m)(n-m-1)}{n(n-1)}\),代入 \(m=\frac{n}{\sqrt 2}\) 得到 \(\frac{1}{2}\)。
令 \(P(n)\) 为大小为 \(n\) 的图得到正确答案的概率,此时有 \(P(n)=1-(1-\frac{1}{2}P(\frac{n}{\sqrt 2}))=P(\frac{n}{\sqrt 2})-\frac{1}{4}P^2(\frac{n}{\sqrt 2})\)。
结论是正确概率为 \(\Omega(1/\log n)\)
解法一:
重新令 \(n\) 为递归深度。假设 \(p(n)=\Omega(n^k)\) 其中 \(k\) 为常数,那么 \(p(n+1)-p(n)=\Omega(n^{k-1})\),另一方面由递推式可知 \(p(n+1)-p(n)\sim p^2(n+1)\sim \Omega(n^{2k})\),于是解得 \(k=-1\),从而 \(p(n)=\frac{1}{n}\),而递归深度是 \(\mathcal{O}(\log n)\),所以正确的概率是 \(\Omega(\frac{1}{\log n})\)。
解法二:
令 \(q(n)=4/P(n)-1\),可以化简为 \(q(n)\leq q(\frac{n}{\sqrt 2})+1+\frac{1}{q(\frac{n}{\sqrt 2})}\),从而 \(q(n)\) 的上界 \(Q(n)=\log_{\sqrt 2}n+\frac{1}{Q(\frac{n}{\sqrt 2})}+\frac{1}{Q(\frac{n}{2})}+\cdots\)。每次递归 \(Q\) 至少 +1,所以后面那一坨 \(\leq 1+\frac{1}{2}+\frac{1}{3}+\cdots=O(\log \log n)\) 的,所以 \(Q(n)=O(\log n)\),从而 \(P(n)=\Omega(\frac{1}{\log n})\)。
6. QOJ4896 Alice、Bob 与 DFS
先考虑只有白点怎么做,把游戏过程看成这样:
- 初始先将 \(r\) 的所有出边倒序放入栈,如果 \(r\) 为黑色那么放入的为红色,否则为粉色。
- 每次可以 pop 掉栈顶的若干元素,可以在某个粉色 pop 后停下,pop 了红色必须停下,如果全粉色可以全 pop 完直接结束游戏。然后将最后 pop 的点 \(x\) 的出边倒序放入栈,根据 \(x\) 黑白决定放入点是红粉。
先考虑只有白点怎么做,假设从 \(x\) 开始走的游戏的 sg 是 \(f_x\)。对于一个栈 \((v_1,v_2,\cdots ,v_k)\),现在计算如果 pop \(v_k\) 并把其出边倒序压入栈所到达的状态,其 SG 值是多少。此时发现 \(v_k\) 前面的那些点实际上是在求 \(f_x\) 前保证如果走完 \(x\) 可以到达一个集合 \(S\) 内的任意 sg 值,而这个 \(S\) 就是 \((v_1,v_2,\cdots,v_{t-1},A(v_t))\) 这样一个栈的 sg 值,其中 \(A(v_t)\) 指的是将 \(v_t\) 的出边倒序压入栈。
由此可以定义 \(g(u,S)\) 表示从 \(u\) 结束后还能到达 \(S\) 中任意一个 sg 值的状态,其 sg 值是多少。那么所求的实际上是 \(g(u,\{0\})\)(没有出边的点 sg 值为 1)。这样就得到了求 \(g(u,S)\) 的方法:
- 倒序遍历每一个出点 \(v\):
- 计算 \(s'=g(v_i,S)\);
- \(S\gets S\cup s'\)。
- 最终 \(g(u,S)=\text{mex}(S')\),这里 \(S\) 是最初的,\(S'\) 是最后的。
此时可以归纳证明 \(g(u,S)=\text{mex}^{g(u,\{0\})+1}(S\backslash\{0\})\) ,其中 \(\text{mex}\) 的上标指的是第几个没出现的数。
一个直观的理解是它相当于对 \(g(u,\{0\})\) 中的每个状态都接了 \(S\) 中作为后继,那么相当于 ban 到了 \(S\) 中的值,再在剩余的里面求 \(g(u,\{0\})\)。
归纳的证明:看成每次将没出现的第 \(g(v_i,\{0\})\) 个数加入到 \(S\) 中。同样可以发现相当于 ban 掉初始 \(S\) 中的值去求 \(g(u,\{0\})\)。
排除掉没有出边的黑点(可以将其直接视作白点),对于一个黑点,它 \(g(u,S)\) 的求解是这样的:
- 倒序遍历每一个出点 \(v\):
- 计算 \(s'=g(v_i,S)\);
- \(S\gets \{s'\}\)。
- 最终 \(g(u,S)=\text{mex}(S')\)。
\(S'\) 只有一个元素,所以黑点 \(g(u,S)\in \{0,1\}\) 并仅取决于 \(S'\) 中的是不是 \(0\),往回倒推 \(S\),发现仅需要关注 \(S\) 包不包含 \(0\)(由于已经排除没有出边的情况,所以 \(S\neq \varnothing\))。
这时原来归纳证明的结论不行了,即使改为这样
只有白点之间可以归纳,黑点不满足其归纳假设,需要特殊考虑黑点的贡献。
就可以了,可以验证黑点满足,然后直接套用上面那个归纳就是对的?
7. 300iq contest 2 H Honorable Mention
\(f_{[l,r]}[0/1][0/1]\) 表示 \([l,r]\) 区间内,是否决定选择前缀与前面的后缀连成一段 / 是否决定选择后缀与后面的前缀连成一段,凸的,直接闵和合并。线段树的结构分治处理出来就行。
先 wqs 二分,然后选一个段就会有一个 \(-mid\) 的贡献,求最值。把线段树上的这些节点找出来,在凸包上二分得到每个节点 \([0/1][0/1]\) 的取值,然后再做个线性 dp 的合并就行。这样是 \(\mathcal{O}(n\log A\log^2 n)\) 的。换成整体二分,在整体二分上 bfs,每一层的时候对每个凸包记个指针,就是俩 log。
8. P5470 [NOI2019] 序列
没看出费用流模型比较失败。瞅了一眼 srf 题解里的图。
然后开始模拟费用流,简单画画就讨论完了?/xia 推导的核心:
- 有费用的边一定不会推流;
- 一个物品的两个反向边不会同时存在。
9. CF1427G One Billion Shades of Grey
10. P6631 [ZJOI2020] 序列
照着 dxm 论文有一步步推的/wq Code
11. [Aizu 2230] How to Create a Good Game
原问题:
令 \(z\) 为 \(d_n-d_1\leq dis_n\) 的对偶变量,\(f_{u,v}\) 为 \(x_{u,v}+d_u-d_v\leq -w_{u,v}\) 的对偶变量。其中 \(x_{u,v},d_u\) 为变量,前者 \(\geq 0\),后者无限制。
对偶之后:
注意原问题的变量 \(d\) 是无限制的,所以它对偶之后的限制应为 \(=0\)。
那么先强制让 \(f_{u,v}=1\),让 \(n\to 1\) 连边费用为 \(dis_n\),\(u\to v\) 连边费用为 \(-w\),跑个网络流去修正这个网络预流的流量就行(其实就是循环流)。
12. 300iq contest 2 J Jiry Matchings
二分图最大权匹配,凸的。所以 dp \(f[x][0/1][]\) 表示 \(x\) 子树内,\(x\) 没有被选 / 可能没被选也可能被选,一共选了几个匹配。合并是 \((\max,+)\) 卷积,位移,取 max,之类的操作。这里不能启发式合并因为合并是 \(\mathcal{O}(siz_x+siz_y)\) 的。序列上的情况启发我们要树分治,但是不能把一个连通块里每个叶子的存在与否给记下来。
其实树剖也是一种树分治!!重链剖分之后,轻儿子用哈夫曼树合并(直接中点分治也行),把一条重链上挂的轻子树都合并上来之后再对这条重链就行中点分治合并,分治的过程中记录左右端点是否被选。
13. P3347 [ZJOI2015] 醉熏熏的幻想乡
只会贺题解代码/ll
考虑极小的 \(\Delta t\) 内,每个左部点的费用是其代价关于当前流量的导数值。类似骑行川藏那个题,能意识到的是,还没看到上界的费用应当都相同。答案就是费用关于流量围成的面积。
给出总流量求费用有点难,因为不太能确定每个左部点自己的流量。但是如果已知费用 \(x\) 的话,能够知道每个人的流量上限 \(\min(c,\frac{x-b}{2a})\),跑一下最大流就知道每个人此时怎样流是最优的。
我们需要还原出整个图像,所以需要把 流量——费用 的直线给求出来。稍微分类讨论一下:
- 对于不满流的左部点,\(c\) 再大,流量上限再大,流量不会变得更大,所以将流量加到截距里面。下面考虑满流的:
- 如果 \(a=0\) 说明它是会在 \(c=b\) 的时候突然被选中然后流满,是一个斜率突增的点,这个突增的问题稍后再讨论。它也是此后保持流满 \(c\) 的状态,加到截距流满。
- \(a\neq 0\),看 \(\min(c,\frac{x-b}{2a})\) 取到的是 \(c\)(已经 bound 住不能再涨)还是 \(\frac{x-b}{2a}\),前者也是不会再变直接加到截距里面;后者在费用增大的时候依然会增加流量,\(x\) 每增大 1 流量增大 \(\frac{1}{2a}\),加到斜率,然后根据它过当前这个点算出对截距的贡献。
能够算出某个位置处的直线,需要意识到的是除了徒增点,被徒增点划分出的区域内部是上凸的(考虑各个左端点是上凸的,加起来还是上凸的)所以根据最左侧和最右侧的直线算出中间的交点,再算这个交点旁边的直线就行。注意不能直接按照顶点来算,需要加个 eps 偏移量。
跑最大流不能写分数类,需要用小数跑,那么求不满的流就是考虑最大流 = 最小割,而最小割就是左侧的满流边,和右侧的不能到达的满流边。所以左侧未满流点的流量就是右侧的割边的流量。
还有一些细节看 Alex_Wei 的题解吧/ll