1. ARC130E Increasing Minimum
好莫名奇妙的题,不知道省选前为啥没做出来。
直接变成分段问题:第 \(i\) 段的表示说这些元素在遍历到(没有做加法前)取值都为 \(i\)。
一个合法的分段方式需要满足:
-
\(x\) 在一个段里不重复出现。
-
若 \(x\) 在第 \(i\) 段出现,则必须在 \(j\gt i\) 段也出现。最后一段不适用这个规则。
先构造任意一组合法解:设 \(dp(i)\) 表示能否将 \([1,i)\) 分段。考虑向后转移:先判掉 \([i,n]\) 作为最后一段是否可行。如果 \(i\) 不在最后一段,则枚举 \(j\),令 \([i,j]\) 成一段。由条件 \(1\),\(j\) 有一个上界。由条件 \(2\),\(j\) 有一个下界。这样,每个 \(i\) 向后导出的 \(j\) 都在一段区间 \([L_j,R_j]\) 内。
从后往前 dp,可以求出每个点 \(i\) 是否能到达 \(n\)(也就是 \([i,n]\) 能否划分干净),删去那些不能到达的点,它们不可能成为决策点。为了让字典序的解最小,直观感受应该是每一段尽可能地长:事实上从 \(1\) 开始每一步走最远的可行决策点即可,因为 \([L_i,R_i]\) 这个区间是双单调的,保证了得到的就是字典序最小的解。
时间复杂度 \(O(n\log n)\)。
2. qoj8943 Challenge Matrix Multiplication
有点脑筋急转弯的题。
这个条件很容易发现可以把图剖成 \(\le 60\) 条链,一个点可能会出现多次但 \(60\) 条链就足够包含所有点(除了孤立点)。
而对于 DAG 上的一条链,我们可以在 \(O(n+m)\) 的时间内求出每个点的可达点数。
道理很简单:这条链上后面的点能到的位置,前面的也能到。所以只用求出每个点,求出链上最靠后的能到达的它的点即可,可以很容易拓扑排序时算出。最后跑个后缀和即可。
3. qoj8942 Sugar Sweet 3
我哪会这个呀?
翻译一下题面其实就是在搞摩尔投票啊。。所以一个序列能消干净当且仅当长度是偶数且没有一个绝对众数。
研究一下相邻的两次栈为空的时刻:那这一段时刻内栈里一定都是同一个元素,且这个元素恰好出现 \(\frac{len}{2}\) 次。
所以思路是这样:我们把这 \(\frac{len}{2}\) 个元素标记为主元位。则 \(A,B,C\) 三类一共恰好选出来 \(\frac{n}{2}\) 个主元位。枚举一下 \(A,B\) 这边选了多少个,那么 \(C\) 那边也就自然确定。对于 \(A/B/C\) 三类,我们都需要把它这些主元分成若干组。令 \(f_{i,j}\) 是有 \(i\) 个 \(+1\) 和 \(i\) 个 \(-1\),有多少种序列使得整个过程中前缀和非负且恰好有 \(j\) 次为 \(0\)。\(f_{i,1}\) 就是反射容斥(卡特兰数),而 \(f_{i,j}\) 直接暴力算就能做到 \(O(n^3)\),这里 \(n=500\)。
有了 \(f_{i,j}\) 以后,我们枚举了 \(a+b+c=\frac{n}{2}\),那其实就是把 \(f_a,f_b,f_c\) 做个 egf 卷积。考察 \([x^i]\) 项系数就是恰好 \(i\) 次消空的个数。不过在此之前我们还剩下 \(A-a/B-b/C-c\) 个非主元没有放进对应位置:每个非主元不能放进自家的主元所在的组里,那就枚举 \(A\) 给 \(B\) 放了多少个剩下的都能 \(O(1)\) 计算。所以枚举 \(a,b,c\) 后这个东西可以 \(O(n)\) 算,不成麻烦。
瓶颈就在枚举 \(a,b,c\) 后你相当于要做个卷积这样就是 \(n^3\log n\) 了。但是我们有插值大法。。而且你不用枚举 \(a,b\) 后再插值插回来,直接把每个 \((a,b,c)\) 代表的多项式乘上系数相加最后插一下就行。。这样最后只需要 \(O(n^2)\) 插值一次。
复杂度还是 \(O(n^3)\) 但是跑的非常快,毕竟 \(n=500\) 且好多小常数。
4. CF2006E Iris's Full Binary Tree
感觉转化有点平凡?显然就是不断加叶子,求一个 \(deg\le 2\) 的点,使得它到最远的点的距离最小。
“到最远的点”的表述就容易想到直径状物。有一个很好写的维护方法:一个点到最远点的距离就是直径的一半加上它到直径中点的距离。前者很好维护,后者的话考虑加一个叶子直径中点也最多移动一步,令 \(f_i\) 表示 \(i\) 到直径中点的距离那就能表述成子树加的形式。线段树维护一下就能 \(O(n\log n)\) 了。
5. CF2006F Dora's Paint
感觉思维难度含量不大,代码实现很恶心。
给一个矩阵,怎么算它的 \(f\)。正着做不好做,考虑时光倒流:每次删去一个全是 \(2\) 的行/全是 \(1\) 的列即可。
比如说假设一开始有 \(k\) 个全是 \(2\) 的行,我们肯定就是贡献 \(k!\) 的方案数,然后删去这 \(k\) 行,变成子问题。一开始有 \(k\) 个全是 \(1\) 的列也是同理的。
发现这样的话有一个很良好的性质:我们把每一行里 \(1\) 的位置提取出来,按照个数从小到大 sort 一下,则应该是一个子集包含的关系。
那给定这样一个排序处理好的信息怎么去快速算方案数呢?我们假设这个矩阵有解(也就是满足子集包含关系),那不难看出:假设有 \(k\) 个子集大小一样就贡献 \(k!\),假设相邻两个集合大小差异为 \(k\) 也贡献 \(k!\)。
再仔细想想发现有 corner case:子集大小为 \(n\) 的时候不贡献,然后从空集到 \(S_1\) 有贡献,但是 \(S_n\rightarrow \{1,2,...,n\}\) 也是没贡献的。
会算方案数就很好做了:还是先把集合排序然后讨论一下是加一个 \(1\) 还是删一个 \(1\)。以前者为例,枚举一下修改的是 \(S_i\),考虑 \(S_i\) 后面第一个集合大小严格大于他的 \(S_x\)(如果没有那就是 \(x=n+1\),\(S_x\) 为全集),以及除了 \(i\) 以外第一个大小严格小于 \(S_x\) 的集合 \(S_y\)(如果没有那就是 \(y=0\),\(S_y\) 为空集)。那么我们加入一个元素后要满足 \(S_y\subseteq S_i\subseteq S_x\)。因此 \(S_y\) 中至多有一个元素不在 \(S_i\) 中,再分到底有没有两种情况讨论,就能知道往 \(S_i\) 里添加一个元素后依然满足偏序关系的方案数。当然我们还需要其他位置保持满足偏序关系不变。对于方案数的计算和合法性判断,只有 \(O(1)\) 处位置会微调,大概就是这个道理。
我使用了好写一些的 \(O((n+m)\log)\) 实现。但精细实现是可以做到 \(O(n+m)\) 的。
6. qoj8938 Crawling on a Tree
为啥过这么少呀,我觉得这个题应该是没有 H 和 I 难呀。。
研究一个人的行走路线:一定是类似 dfs 状物的,每条经过的边都恰好走 \(2\) 次,除了根到最后一个点的路径是只走一次的,那个人就会停留在最后一个点。
于是设 \(f(u,x)\) 是 \(u\) 节点处有 \(x\) 个人,而且他们都会停留在 \(u\) 子树内,不会回到 \(u\) 子树外的答案。
当然 \(x\) 个人可能是不够的,所以我们需要引入一些回到 \(u\) 子树外的人,使得每个点经过的次数有保证。
可以证明,引入的人数一个下界是 \(\max\{0,mx_u-x\}\),其中 \(mx_u\) 是子树内 \(c\) 的最大值。而这个值也能作为上界,可以通过在最优解中自底至顶归纳来证明。
那就很简单了,显然对于一个 \(u\) 可行的 \(x\) 有个上下界,然后说我们只要闵和卷一下就行了。这个看着就很凸。然后 \(O(nm)\) 这个是,肯定可以用平衡树这种东西优化。
7. ABC367G Sum of (XOR^K or 0)
考虑 \(m=1\) 怎么做:尝试对于每个 \(v\),求出有多少个子序列的 xor 结果为 \(v\)。这是很像 fwt 做 xor 卷积的状物。
相当于有 \(n\) 个 \((1+x^{\{a_i\}})\) 这样的多项式,我们需要对每一个分别 FWT,点乘,最后 IFWT 一次。
而 \(1+x^{\{a_i\}}\) 做一次 FWT 的结果 \(F(x)\) 还是很容易描述的,只关注 \(n\) 和 \(a_i\) and 结果大小的奇偶性。
所以如果我们想求 FWT 数组全部点乘后 \([x^m]F(x)\) 的值,就是在统计有多少个 \(a_i\),和 \(m\) and 的结果大小是奇数/偶数。
这个怎么计算?很巧妙的一点是:如果对 \(a_i\) 的桶去做 FWT,那么 \([x^m]F(x)\) 其实就是,和 \(m\) and 的结果大小是偶数的,减去和 \(m\) and 的结果大小是奇数的;而我们知道两者和为 \(n\),又知道了差,就很容易求出来个数了。
这样就知道 FWT 数组每一项的值了,IFWT 回去即可。这是 \(m=1\)。
\(m\gt 1\) 怎么办呢?相当于我们不再是 \(\prod(1+x^{\{a_i\}})\) 了。而是改成:任选一个长度为 \(m\) 倍数的子序列,求 \(\prod x^{\{a_i\}}\) 的结果然后相加。那体现在刚才的过程中,我们对于一个 \(v\) 已经知道了多少个元素和 \(v\) and 得到奇数多少个得到偶数。我们现在相当于要从这些数里面总共选 \(m\) 的倍数个,那假设从奇数那边选的个数 \(\bmod m = i\),从偶数那边就得选 \(\bmod m = m-i\) 的个数。因此设 \(F(cnt,i)\) 是 \(\sum_{x\bmod m=i}\dbinom{cnt}{x}\),处理出来 \(F\) 以后就可以 \(O(m)\) 算一个位置的答案。而 \(F(cnt,i)\) 容易 \(O(nm)\) 递推出来,原理还是利用加法恒等式。
时间复杂度 \(O(nm+2^Lm)\)。
8. qoj4215 Easiest Sum
其实这个题以前甚至都做过一遍了,但理解的还是不够深刻,所以寄了。。
问题在于求一项 \(g(k)\) 其实都是很难的,没有办法直接贪心 / DP 去做。考虑二分答案,检查答案是否能够 \(\le v\)。
那就是,要求出最小步数使得非空最大子段和 \(\le v\)。而这实质上可以写成一个线性规划问题。对偶后等价于求 \(\max f(i)-vi\),其中 \(f(i)\) 是选 \(i\) 个不交非空子段的最大的和。
求出 \(f(i)\) 是经典的分治闵和,而且这是凸的。那对于一个 \(v\),建好凸包以后可以在凸包上二分求答案。这样可以 \(O(\log^2)\) 求一个 \(g(k)\) 了。
实质上 \(g(k)\) 怎么用凸包去描述?对于一个 \(v\),所谓的 \(\max f(i)-vi\) 就是拿斜率 \(v\) 去切凸包得到的截距。那每一个 \(v\) 都可以映射到 \(y\) 轴上一个 \(val(v)\) 的位置,并显然 \(v\) 越小 \(val(v)\) 越大。而 \(g(k)\) 就是最小的一个 \(v\) 满足 \(val(v)\le k\) 的。
那就好做了,\(y\) 轴被划分成了 \(O(n)\) 段管辖区间。随便写点东西搞搞就行。
9. qoj 964 Excluded Min
好厉害的题!!
\(O(qA):\) 考虑这样一个贪心过程:我们维护一个桶,初始每个位置都是 \(-1\)。对于一个序列,把 \(a_i\) 的对应位置加一。然后找到最靠后的一个前缀和 \(\ge 0\) 的位置,这个位置 \(+1\) 就是 mex 的最小值。
\(O(q\sqrt n\log A):\) 莫队。在值域上维护线段树即可。
\(O((n+q)\log)\): 考虑还是要扫描线一下。直接在原序列扫描线不好做,尝试换维。也就是离线,对 \(q\) 个区间维护他们扫到一个极大值的时候的前缀和(这个极大值其实也就 \(10^6\) 级别就足够了)。然后逐步减小这个指针。那么涉及的修改就是:给一个位置 \(x\),把所有包含 \(x\) 的询问区间的值减一。需要查询的是 \(\ge 0\) 的那些区间,他们的答案在此时确定。
我的思考就到这里止步:因为会发现这个修改很困难,相当于是二维平面上的矩形修改了,这还能做啊??
本题最巧妙的点就在这里:假设询问区间满足没有包含关系,也就是 \(L,R\) 双单调,那这个修改就实际上是一维的。而对于两个区间 \(x,y\),如果 \(x\) 包含 \(y\),那么 \(y\) 的答案一定不比他大。也就是说取出区间 \(x\) 之后我们再把 \(y\) 加进待选队列里去考虑即可。这样我们时刻保证了待选区间的 \(L,R\) 是双单调的,始终可以把修改看成是一维的!
至于删除一个区间后加入一些新区间的过程,可以把询问排序后用另一颗线段树,在上面二分来维护。
到底怎么想到这一步啊??
10. qoj4888 Decoding The Message
tmd,这个题我又有一步看不出来啊。
所有方案的乘积就是一个很恐怖的东西,又因为模数的特殊性,尝试从模数出发。
注意到模数是 \(2^{16}-1\),位权是 \(w=2^8\),所以 \(w^2\) 可以看作 \(1\)。换言之,可以把排列数码得到的数的过程换个视角来看:相当于把数分成两组大小为 \(N=\frac{n}{2}\) 的(上下取整就不写了),然后一组的权是 \(1\) 一组的权是 \(w\)。
模数很小所以我们不妨做的恨一点:分解质因数然后 crt 回去。毕竟模合数和模质数是两个级别的。分解结果也很感动,每个质因子都只出现了一次:\(3\times 5\times 17\times 257\)。
实际上有点数学基础的话会发现 \(2^{2n}-1\) 一定有因子 \(2^n-1\) 啊,就是把这个写成 \(255\times 257\) 就很会做了。
因为模 \(255\) 真的特别简单啊:\(w\bmod 255\) 也是 \(1\),那不管怎么排列权值都是固定的。
那如果我说我看不出来 \(3\times 5\times 17\) 放一起这么好算能不能做?其实还是能做,和 mod 257 一样做。
mod 257 就难一点,注意到 \(\phi\) 是 \(2^8=w\equiv -1\)。然后说我们随便选 \(N\) 个数字,把他们放到 \(w\) 的权那一组,方案数都是 \(N!(n-N)!\),注意到 \(n\ge 12\) 的时候这个数字一定是 \(\phi\) 的倍数,那只用考虑 \(n\lt 11\) 的就行,这里暴力做就行。
\(n\ge 12\) 的时候答案不是 \(0\) 就是 \(1\),因为你算 \(0^x\) 和算 \(a^x\) 是不一样的,前者不能用欧拉定理。相当于只需要判是否存在一个方案能得到 \(0\)。前面说了 \(w\) 这个权在 mod 257 意义下是 \(-1\)。那差不多就相当于给你一个 \(p\) 问能否选 \(N\) 个数,凑出来和为 \(p\)。
所以如果你要做 \(3/5/17\),虽然 \(w\) 不是 \(-1\) 但你也可以做一些背包,反正值域太小了。\(257\) 是唯一麻烦的。
这里就有一步看不出来啊,因为注意到物品特别多啊。
就是,如果我们能选出 \(256\) 对二元组,每个元素至多出现一次,且一个二元组的两个元素值不同,就一定有解。
这个相当于是,你先把二元组的 \(x_i\) 都选,\(y_i\) 都不选能得到一个解,然后你可以替换,变量是 \(y_i-x_i\)。
然后 \(256\) 个非零值一定能选出一个子集得到你想要的那个值。所以一定有解。
选不出来 \(256\) 对的情况,把数码按照出现次数排序,除了出现次数最多的那对,剩余的总数不超过 \(2\times 256\),所以跑个背包 bitset 优化就行。。。
11. CCO2021 Travelling Merchant
删去那些到不了环上的点后,变成了求解 \(f(u)=\min_v\{\max\{r,f(v)-p\}\}\)。
令 \(g(u)=\min r\),则 \(g(u)\) 最大的那个点可以证明答案就是 \(f(u)\)。
当确定了这个点的答案后,考虑所有连向 \(u\) 的点,把 \(r\) 修改为 \(\max\{r,f(v)-p\}\) 即可。
重复这个过程就好了。很像过河卒。
12. zr noip round3 D题
题意:给定一个长度为 \(n\) 的排列 \(A\)。询问有多少个长度为 \(n\) 的排列 \(B\),满足 \(B\ge A\) 且 \(B\) 可以被一个栈来完成排序。\(n\le 10^6\)。
先考虑如何判定一个排列能被栈排序,容易发现当且仅当不存在一个长度为 \(3\) 的子序列相对大小关系是 \(231\) 的时候可以完成排序。再考虑 \(A_i=i\) 的情况,打表易得答案为卡特兰数 \(C_n\)。
暴力枚举 LCP 长度 \(i\) 和第 \(i+1\) 位的取值,如何计算答案?首先 \([1,i+1]\) 这部分不能出现 231,假设没有出现了。那么考虑没有出现的数在值域上构成若干个连续段,每个连续段长度对应的卡特兰数的乘积就是答案。这样做到了 \(O(n^3)\)。
发现:从前往后的时候,每次下一个人必须是值域连续段上第一段的。那枚举 lcp 长度后,\(i+1\) 位这边就很好算。这样可以做到 \(O(n^2)\) 的复杂度。
怎么做到更好呢?观察到假设 \(a_{i+1}=x\),那 \(x\) 得位于值域上第一段才行。然后 LCP 增大的时候就会从 \(x\) 这里把第一段分裂为两段。这个很像启发式分裂的过程,如果我们能把复杂度控制在比较小的那一段的长度就很好:如果 \((x,R]\) 是较短的就很好,如果 \([L,x)\) 短,那考虑可以用 \(b_{i+1}\in [L,R]\) 的情况减去 \(b_{i+1}\in [L,x]\) 的情况。后者直接暴力算,前者需要跑一遍卷积,相当于 Catalan^2,众所周知这个东西还是 Catlan(就算是 Catlan^k 其实也能做)。
13. CEOI2023 Tricks of the Trade
第二问真的令人耳目一新啊。。
只考虑第一问是比较常规的:可以猜测固定左端点 \(L\),最优秀的右端点 \(f(L)\) 是单调不下降的。因此用决策单调性分治 + 主席树就可以 \(O(n\log^2 n)\) 解决。
进一步其实可以证明这个代价函数 \(w(L,R)\) 满足四边形不等式:\(w(a,c)+w(b,d)\ge w(a,d)+w(b,c)\),证明也不是很难。
第二问最暴力的想法是:对于每一个 \(w(L,R)=ans\) 的区间,都把能成为这个区间前 \(k\) 大的位置标记。这样是 \(O(n^2\log n)\) 的,效率很差。
而这题告诉我们满足四边形不等式的时候,所需要“关注”的区间很大概率是双单调的。什么意思呢?若 \(a\lt b\lt c\lt d\) 且 \([a,d],[c,b]\) 是 \(w(L,R)=ans\) 的区间,由四边形不等式以及 \(ans\) 的定义,可以得到 \(w(a,c)=w(b,d)=ans\) 同时成立。此时我们不需要考虑 \(w(a,b)\) 这个区间,只需要考虑 \(w(a,c)/w(b,c)/w(b,d)\) 三个区间即可。可以发现这三个区间的 \(L,R\) 就是双单调的。
当所需要考虑的区间是双单调的时候,很自然地利用滑动窗口的思想。用 set 按照 b 的大小维护当前区间内没有被标记过的位置即可。只有 \(O(n)\) 次插入删除,整体是 \(O(n\log n)\) 的。
如何找出上述的所有区间?对每个左端点 \(L\) 维护最靠右的右端点 \(f(L)\)。顺序枚举 \(L\),考虑上一个 \(w(L,f(L))=ans\) 的位置 \(L'\lt L\),则只需要考虑 \(w(L,f(L')\sim f(L))\) 这些区间即可(注意是 \(\ge f(L')\) 而不是 \(\gt f(L')\))。
14. ARC184C Mountain and Valley Folds
好牛逼的题啊。。
先研究折线序列的规律:令 \(0\) 表示谷折,\(1\) 表示山折。
则不妨从对折了 \(1,2,3...,100\) 次的序列递推地生成序列:对折一次得到的序列是 \(0\),两次是 \(0-0-1\),三次是 \(0-0-1-0-0-1-1\)。。。。会发现生成规律就是,第 \(i\) 次对折的话,原来序列有 \(2^{i-1}-1\) 条折痕,把纸条划分成了 \(2^{i-1}\) 段。那么每个段都会插入一条折痕:奇数段是 \(0\),偶数段是 \(1\)。
发现这个生成规律以后,考虑最终的序列:提取出所有奇数位置,则应该形如 \(01010101010101...\)。提取出偶数位置,有递归的这样的一个结论。也就是说第 \(i\) 条折痕的状态可以这样确定:找到最低的一个 \(1\) 的位置,如果其上一位也是 \(1\),那么他是山折,否则是谷折。
有了这样的观察后,考虑设计一个数位 dp 的状物,从低位开始确定 \(i\),最后找到一个最优秀的 \(f(i)\)。
比如说,假设 \(i\) 的最低位是 \(0\),\(a\) 中所有奇数位置,他们的最低位都是 \(1\)。如果 \(i\) 的最低位是 \(1\),\(a\) 中所有偶数位置,最低位就是 \(1\)。
那这些最低位是 \(1\) 的,它们到底是 \(0\) 还是 \(1\) 是取决于次低位的。所以我们不妨枚举 \(i\) 前两位的取值(\(0\sim 3\)),然后对于 \((0/2)\) 或者 \((1/3)\),他们分别能把 \(a\) 序列中奇数/偶数的 \(0/1\) 直接确定掉。那么剩下的数呢?
从这个思路触发设计一个 \(f(a,k)\) 表示只考虑数组 \(a\),然后最低的两位的贡献是 \(+k\)。答案就是 \(f(a,0\sim 3)\) 的最大值。
对于每一个 \(f(a,k)\),根据 \(k\) 的奇偶性,会有一部分 \(a\) 的值直接确定。另一部分我们就要把他们的最低位去掉(也就是除二),然后进入新的子问题。设新的数组为 \(b\),那新的 \(k\) 是多少呢?我们需要讨论 \(i\) 的第三位是 \(0\) 还是 \(1\)。比如说如果 \(k=0/2\),那前者转移到 \(0/2\),后者转移到 \(1/3\)。如果 \(k=1/3\),会发现前者转移到 \(1/3\),后者由于进位了两次,所以会转移到 \(2/4\)。不过好消息是 \(4\) 只会转移到 \(2/4\)。所以 \(k\) 的上限就是 \(4\)。
遗留的问题是整个计算过程中可能的 \(a\) 有多少种?显然可以建出一个 0/1 trie,每个 \(a\) 插进对应的 trie 的位置。一个节点子树整体就作为一个计算过程中出现的数组。因此只有 \(O(n\log A)\) 种可能的数组。对每一种数组我们直接把它 \(k=0\sim 4\) 的答案算出来并一起返回即可。这样就得到了 \(O(n\log A)\) 的解法。
15. CF906C Party
题目中的操作:选择一个人,让他的所有朋友两两之间认识。很眼熟,似乎我们在 USACO 和 CCO 中都有见过。
事实上结论是,把那些做过一次操作的人涂黑。然后建图。原图上两个点 \(x,y\) 认识,当且仅当存在一条路径 \(x\rightarrow y\),使得路径上每个点都是黑的(除了 \(x\) 和 \(y\))。
特判完全图。然后我们至少需要涂黑一个点。根据“认识”的转化条件,图上涂黑的点一定是连通的,不然它们就不可能认识。
现在有一个黑点的连通块。对两个白点 \(x,y\),如果他们都和黑点有连边,就一定能认识。如果一个白点和黑点没有连边,它不可能认识这个黑点。因此我们枚举一个点集 \(S\),如果他是连通块,就把他全部涂黑。然后检查是否每个白点都和 \(S\) 有连边即可。选择最小的一个 \(S\) 就是答案。复杂度 \(O(n2^n)\)。
16. AGC007E Shik and Travel
整个过程就是 dfs 的过程。最小化路费就是最小化 dfs 时两个相邻叶子的距离。因此考虑二分答案 \(lim\)。然后设 \(dp(u,s,t)\) 是从点 \(u\) 出发 dfs 子树,能否第一个叶子是 \(s\),最后一个叶子是 \(t\)。这个状态太浪费了。不如设 \(dp(u,s)\) 是第一个叶子是 \(s\),途中不超过 \(lim\) 的情况下,最后一个叶子到 \(u\) 的距离最浅能是多少。
这样合并就可以树形背包了,因为是二叉树。能做到 \(O(n^2\log)\)。
尝试启发式合并的思想来维护:令 \(p\) 是重子树,\(q\) 是轻子树。当 \(s\in q\) 的时候,状态只有 \(O(|q|)\) 个可以接受。当 \(s\in p\) 的时候,虽然状态有 \(O(|p|)\) 个但是本质不同的 dp 值只有 \(O(|q|)\) 种。对每一种保留深度最浅的 \(s\) 即可。因此可以说明,一个节点的有效状态数是 \(O(|q|)\) 而不是 \(O(|p|+|q|)\) 的。所以合并的时候直接暴力枚举两颗子树的所有状态,跑双指针是可以接受的复杂度。因为可能需要排序,所以复杂度是 \(O(n\log^3)\),常数非常小。
17. ARC176E Max Vector
Ohno,这个题为啥没想出来。
转化一下问题,变成构造 \(x',y'\)。使得 \(x'_i\ge x_i,y'_i\ge y_i\),并且最小化 \(\sum x'_i + y'_i\)。一组约束 \(a_1,a_2,...,a_n\) 即为,\(\forall i,x'_i\ge a_i\) 和 \(\forall i,y'_i\ge a_i\) 必须成立一个。
考虑用最小割来构造这个问题:限制可以这样描述,若某个 \(x'_i\ge a_i\) 不成立,则所有的 \(y'_i\ge a_i\) 都必须成立。
最小割的形式是这样:给定若干组 \((x,y,w)\),限制形如若变量 \(x\) 为真且变量 \(y\) 为假则付出 \(w\) 的代价。
因此设变量 \(A_{i,j}\) 表示 \(x'_i\le j\) 是否成立,\(B_{i,j}\) 表示 \(y'_i\ge j\) 是否成立。限制即为 \(A_{i,a_i-1}\) 向 \(B_{j,a_j}\) 连 \(\infty\) 的边。跑一次最小割即可。
18. qoj4811 Be Careful
很莫名其妙的题,我觉得。
\(mex\) 这种东西不太好多项式解决。不过菊花图的情况我们还是很容易多项式的。因此猜测一个点 \(u\) 的所有儿子节点中,叶子和非叶子是存在本质区别的。
事实上,一个非叶子节点的取值一定不超过儿子个数 \(deg_u\)。而 \(\sum deg_u\le n\)。这启示我们做一个根号分治:设定阈值 \(\sqrt n\),把非叶子的儿子分为 \(deg\le \sqrt{n}\) 的和 \(deg\gt \sqrt{n}\) 的。后者只有最多 \(\sqrt{n}\) 个。
若所有儿子节点的 \(deg\) 都 \(\le B\),我们有一个 \(O(2^B)\) 级别的做法,直接按顺序考虑每个儿子的选择,并且状压 \(\le B\) 的数值是否出现过即可。若一共只有 \(\le B\) 个儿子节点(非叶子),我们同样也有一个 \(O(2^B)\) 级别的做法,直接按照值域从小到大枚举,并且记录哪些儿子的取值已经确定。这个 DP 的转移需要注意一下:枚举子集复杂度是 \(O(3^B)\) 级别的,考虑用类似 sos dp 的形式转移复杂度就正确了。这两个 dp 都需要考虑一下叶子的加入。
两个 dp 很难独立去做:我们在做第一个 dp 的时候,就需要 \(O(2^cnt)\) 地记录那些 \(deg\gt B\) 的节点哪些使用了,同时又需要 \(O(2^B)\) 地记录 \(\le B\) 的值哪些出现了。在做完第一个 dp 后,我们才会把它的结果扔进第二个 dp 中,第二个 dp 的复杂度倒确实是 \(O(2^cnt)\) 级别的,因为我们不关注 \(\le B\) 的那些值是否出现了。
所以设阈值为 \(B\),\(deg\gt B\) 的点有 \(C\) 个,复杂度就是 \(O(2^{B+C})\) 级别的,当然还要带一些多项式。
结论是最优秀的 \(B+C\) 一定是 \(\le \sqrt{2n}\) 的。刚才我们得到的 \(2\sqrt{n}\) 还不够优秀。怎么分析呢?
假设我们得到了最优秀的 \(B\),则 \(B-1\) 处至少有一个点,否则把 \(B\) 变小 \(B+C\) 严格减小,同样的 \([B-2,B-1]\) 处至少有两个点,\([B-3,B-1]\) 处至少有三个点。所以和最小的方法就是 \(1\sim B-1\) 处各有一个点。类似地分析套用在 \(\ge B\) 的部分的身上。\(=B\) 的点至多有两个,\([B,B+1]\) 的点至多有三个,\([B,B+2]\) 的点至多有四个。。。总而言之,令 \(D=B+C\),则这个方案的 \(deg\) 之和大概是 \(1+2+...+D=\frac{D(D+1)}{2}\) 级别的,所以可以得出 \(D\) 的上界是 \(O(\sqrt{2n})\) 级别的。
那代入 \(n=200\) 也就是差不多 \(20\),而且好像还挺卡不满的。反正这个题就是,很神秘。。
19. 湖北省选模拟2023 棋圣
先考虑 \(k=2\) 的情况。一般图上还是有点复杂,于是考虑树/简单环这样的特殊情况。
如果是树,那两个点要么距离不变,要么距离 \(-2\)。所以距离之间的奇偶性是确定的。联想到二分图:初始位于黑点的棋子和位于白点的棋子是不可能重合的。因此若两个棋子一开始都位于黑/白点上答案为 \(0\),否则答案为最大的那条边的边权,这总是可以做到的。
环呢?偶环和树没有区别,奇环的话就无所谓两个棋子初始的位置了。
对于 \(k\gt 2\) 的情况呢?如果图存在奇环,我们一定能做到让所有黑棋子聚在一起,白棋子也聚在一起。最后它们一起去寻找一条最大的边即可。如果存在偶环,发现除非是一条链,否则我们能做到让所有位于黑点的棋子聚在一起,位于白点的棋子聚在一起,最后也是去寻找一条最大的边即可。唯一特殊的就是链的情况。
注意到此时棋子间的相对顺序不发生变化:不妨记录差分。能做的就是选择一个差分 \(\ge 2\) 的位置让他减二。随便设计一个 dp 就好了。
20. 联合省选2021 图函数
好久远的记忆啊。。。
给定一张图怎么算 \(h\)?把动态的过程变成静态的过程:\(x\) 能对 \(y\) 有贡献 \((x\le y)\) 当且仅当存在 \(x\rightarrow y\) 以及 \(y\rightarrow x\) 的路径使得路径上所有点编号都 \(\ge x\)。
把删边反转看成加边。现在建出最终的图 \(G\),把一条边的出现时间看作边权。则我们就是对每一对 \((x,y)\),想让 \(x\rightarrow y\) 和 \(y\rightarrow x\) 的路径上边权最大的边尽可能小。
考虑 floyd 直接倒着加入每个点,加入到 \(x\) 时 \(x\rightarrow y\) 和 \(y\rightarrow x\) 点对的答案就是想要的。
这个做法是 \(O(n^3+m)\) 的能过也是神人了,不能只给 \(44\) 分吗。
更优秀的做法?那就只能考虑换个角度了,从加点变成加边。维护 \(f(x,y)\) 表示 \(x\) 是否当前可达 \(y\)(其中 \(x\le y\) 且只能走 \(\le x\) 的节点)。加入一条边 \(u\rightarrow v\) 的时候,只对于那些 \(x\le min(u,v)\) 的人,更新 \(f(x,*)\) 的值。可以暴力枚举这样的 \(x\):然后若 \(f(x,v)=1\) 显然 \(u\rightarrow v\) 这条边就无意义了。现在假设 \(f(x,v)=0\)。若 \(f(x,u)=1\),我们现在就会让 \(f(x,v)=1\),并且会让一些 \(v\) 能走到的点 \(w\) 也变成 \(f(v,w)=1\),跑一遍 bfs 即可。若 \(f(x,u)=0\),则当后续 \(f(x,u)=1\) 的时候这条边就会用上,因此先加进 vector 里。这样得到一个 \(O(nm)\) 的做法,应该是数据范围里想给的 \(80\) 分。
进一步地优化?应该很容易看出来能 bitset 搞一手吧。\(m\) 可以认为上限 \(n^2\) 所以就是 \(O(\frac{n^3}{w})\) 的。在稠密图里表现相当厉害啊。需要注意一下就是反图也要这样搞一手。
21. ARC144E GCD of Path Weights
看到这个题我们 JCY_std 就要说了:这个我会!
这种什么所有环的 gcd 啊,所有 path 的 gcd 啊。全都是一个套路:首先需要转成带边权。然后先考虑定权值的情况:假设所有 path 都是 \(g\) 的倍数,当且仅当可以给每个点标号 \(d_u\)。使得对于每条边都有:\(d_v\equiv d_u+w(u,v)\pmod g\)。那其实给一颗生成树(有向边看成无向边)你就可以知道这个弱连通块每个人的 \(d\) 的值了。接下来要做的就是对于剩下的每条边,把 \(d_v-d_u-w(u,v)\) 取个 \(\gcd\)。
带问号呢?那这些边随便取啊就当不存在就行了啊。。。
22. SNOI2024 拉丁方
先学一个二分图边染色的做法!zhk 告诉我还有高妙做法并且还有更难的一个题。但是我的大脑很难理解啊。
先看 \(C=n\) 的部分分。长得就很像一定有解啊!
如果建二分图的话,那就是每个元素朝还没出现的列去连边。这样搞出来是一个 \(n-C\) 正则二分图,非常滴优美!看着就很像能划分出 \(n-C\) 组匹配的样子其实。我还真不会求,很简单,我们有二分图边染色,直接跑染色不就是了!
\(C\lt n\) 的话很自然的想法就是去先补全这些行。还是建个二分图出来。这次是元素向没出现的行染色。它显然不是个正则的图。但我们还是跑一边二分图边染色就行。道理何在?因为一共有 \((n-C)R\) 条边和 \(R\) 个右部点。所以色数一定 \(\ge n-C\)。而如果有解可以推出必定存在一组 \(n-C\) 种颜色染色的方案,另一方面有 \(n-C\) 种颜色染色的方案,必定每种颜色都出现 \(R\) 次,刚好凑成一列。
二分图边染色这里也写一下:结论是 \(d=\max deg_u\) 种颜色就足够了。构造过程就是不断加边。考虑如果 \((u,v)\) 加不进去一种颜色了,找一种颜色 \(c_1\) 是 \(v\) 这边没出现过的,\(c_2\) 是 \(u\) 这边没出现过的。然后直接染上 \(c_1\)。此时 \(v\) 这边会有矛盾,把矛盾的边换成 \(c_2\)。还有矛盾就又换成 \(c_1\)。。。重复这个过程,\(O(nm)\) 做完了。。。