2025.7
看取富贵眼前者,何用悠悠身后名。
代码源 day1t1.Tree
场上看了这道题两个小时啥都不会,在梦游。
先找一个答案的下界,设叶子数量为 \(k\),则下界为 \(\lceil\frac k2\rceil\)。考虑已经加入了所有非叶子的点,先将所有黑色的叶子加进去再删掉,然后把所有白色的叶子加进去,这个过程中值域变化至少为 \(k\),因此有 \(\lceil\frac k2\rceil\) 的下界。直接猜下界就是上界然后构造即可。
构造类似 EC-Final 的 I,出题人也是同一个。整棵树可以被 \(\lceil\frac k2\rceil\) 条叶子到叶子的链覆盖,由此将整棵树分成 \(\lceil\frac k2\rceil\) 个集合(如果一个点在多条链上就分进任意一个集合),注意到连通块和某个集合的交是集合连续的一段,因此对集合黑白相间染色即可,可以根据当前黑白点数之差动态调整染色策略。
链覆盖是经典的,第 \(i\) 个叶子和第 \(i+m\) 个叶子配对即可。有一万种方法在 \(O(n\log n)\) 内求出集合划分。并查集维护树上第一个没被染色的祖先可以做到 \(O(n\alpha(n))\)。
上面的做法并不人类。考虑二分答案,然后树上可以用一个 dp 来 check,一个点的支配对上界是 \(O(n)\) 个,状态数是 \(O(n^2)\),转移是树上背包。支配对可以更进一步分析到 \(O(1)\) 个,大体而言关心强制选子树根后设黑色最多减去白色最多为 \(x\),则最优情况下 \(x\in[-2,2]\),因为我们可以将子树整体异或 \(1\) 来将 \(x\) 取相反数。
这里的分析和 CF1824C 有异曲同工之妙。
P12558[UOI 2024] Heroes and Monsters
\(O(n^3)\) 是简单的,枚举 \(|S|=k\),贪心匹配,\(f_{i,j}\) 代表前 \(i\) 个选了 \(j\) 个放进 \(S\) 中的方案数。这个 dp 实际上是在同时维护 \(S\) 中和不在 \(S\) 中的数的合法性。设 \(i\) 是 \(a_i<b_k\) 的最大的 \(i\),注意到 \(a_{1\sim i}\) 不在 \(S\) 中的数必然合法,\(a_{i+1\sim n}\) 中在 \(S\) 的数必然合法,此时这个 dp 看上去就在干很多没有用的事情。我们对在 \(S\) 中的数的前缀和不在 \(S\) 中的数的后缀分别 dp,最后枚举 \(k\) 后在 \(i\) 处合并即可。时间复杂度 \(O(n^2)\)。
QOJ8775 MountainCraft
神秘题,脑筋急转弯。
斜线的覆盖长度等价于横线的覆盖长度乘上 \(\sqrt2\),直接线段树维护即可。
UOJ840 龙门考古
深刻的题目,不过做的时候仍然在梦游,连 \(c\) 已知都没有注意到。
考虑 \(O(2^n\rm{poly}(n))\),枚举集合 \(S\) 以后考虑如何填能使字典序最小。贪心发现 \(c_i=0\) 的位置一定填当前没填的最小值,对于 \(c_i=1\) 的位置,枚举填哪个数后检查能否给后面的每个 \(c_i=1\) 都分配一个数即可。
实际上这个贪心可以引出一个重要结论:所有不可辨认的非前缀最大值必然递增。因为交换逆序对后不会改变是否合法,字典序会变小。
此时就可以做 \(b_1=n\) 了,对 \(b_{2\sim n}\) 的上升子序列计数后乘上 \(b_1\) 选或不选带来的系数 \(2\) 即可。
现在只需分析所有前缀最大值。我们沿用上面调整的思路,思考什么情况下在前缀最大值上进行交换能保持合法性。设 \(c_i=1\),\(x\) 是最小的 \(x>i\) 且 \(c_x=1\) 的位置,\(v\) 是 \(b_{1\sim x-1}\) 中的次大值。此时 \(b_i\) 支配了整个 \(b_{1\sim x-1}\),容易发现与其交换能保持合法性的 \(b_j\) 必须满足 \(j>x\) 且 \(v<b_j<b_x\),注意到前者被后者所蕴含。因此我们找到了一个必要条件,当前缀最大值 \(i\) 不可辨认,则所有的 \(v<b_j<b_x\) 且 \(j\neq i\) 的 \(b_j\) 需要可以辨认。
大胆猜测这是充分的。回顾暴力做法中是如何填数的,我们只需说明每个不可辨认的前缀最大值位置不能填上更小的数,不妨找到一个其对应的 \(b_x\) 确定下来的 \(i\),如果 \(i\) 处不填 \(b_i\) 的话,只能填一个 \(\le v\) 的数,进而去考虑 \(b_i\) 填在哪,不难发现无处可填,因此 \(b_i\) 也会被确定下来。
至于为何只需说明前缀最大值不能填上更小的数,仍然考虑填数过程,不难发现当前缀最大值不填上更小的数后我们是在将 \(c_i=0\) 的位置填上能填的最小数,因此无需考虑。
我们已经得到了合法集合的充要条件,在值域上考虑一个 dp。每个前缀最大值是否可以辨认只取决于 \((v,b_x)\) 中是否有数不可辨认,因此可以有一个 \(O(n^2)\) 的 dp,\(f_i\) 代表目前最后一个没法辨认的非前缀最大值为 \(i\),转移在值域上考虑即可。注意到所有前缀最大值的 \((v,b_x)\) 是不交的,因此可以树状数组维护转移,时间复杂度 \(O(n\log n)\)。
UOJ750 小火车
考虑鸽巢原理,将一个子集放进模 \(p\) 后的桶中,一定会有一个桶装多个子集,如果能求出来 \(l\sim r\) 桶中一共装了几个子集就可以二分了。这可以折半搜索后双指针。时间复杂度 \(O(2^{\frac{n}2}\log p)\)。
一个经典问题
\(n\) 堆球,每次从不同两堆中取出两个配对,最多配多少对。
首先若存在绝对众数,则答案为总数减去绝对众数,构造显然。否则答案为总数除以 \(2\) 下取整。这显然是上界。Network_Error 给了一个构造,每次从最多的两堆中选出两个球配对。归纳说明除非取完之后只剩一个球,否则仍然不存在绝对众数。
代码源 day2t1.pairing
场上过了第二问。NOI 肯定不会出这么没道理的题,第一问和第二问差不多是两个题了。
第二问的做法非常神秘,感觉能想出来这种东西比较玄幻。首先有一个必要条件是将能配对的点对之间连边,那么每个连通块大小需要是偶数,猜测这是充分的,构造即为第一问。于是暴力就是删去每个点后看每个连通块大小是否为偶数。问题在于边数太多,网格图的经典做法是行和列连边,此时每个点就是新图上的一条边,等价于判断删去一条边后每个连通块边数是否为偶数。这可以 tarjan 直接维护。时间复杂度 \(O(n)\)。
std 的做法是直接考虑原图,删去一个点后的连通块信息可以从圆方树上得到,因此只需要建原图的任意一棵圆方树即可。现在唯一问题在于边数太多,因为一行上的每对点都要连一条边。圆方树实际只需要一张点双连通性和原图等价的图,因此一行直接连成一个环即可。
考虑第一问。任取原图的一棵生成树,从下向上构造。首先将一个点儿子中能配对的尽可能配对,此时有三种情况:
- 所有儿子均能配对。继续向上构造。
- 剩下一个儿子。将该点和儿子配对后向上构造。
- 剩下两个儿子。此时必然满足父亲和某个儿子存在一条非树边,将这条非树边变成树边,该点与另一个儿子进行配对。这样做完以后得到的仍然是一棵树。
至于如何求出生成树,可以直接套用第二问的做法。不过生成树只关心两个点的连通关系,因此连成一条链即可。
烧瓶
给定 \(n\) 个点的树。问总点权为 \(m\) 且每个点点权非负的 \(\binom{n+m-1}m\) 种情况中,编号最小重心的和。\(n\le 3\times10^5,m\le 5\times10^6\)。
先来考虑 \(m\) 是奇数的情况,此时重心必然只有一个。枚举重心 \(u\),那么方案数就是总方案数减去任意一个子树大小超过 \(\lfloor\frac m2\rfloor\) 的方案数,记 \(f_S\) 代表子树大小为 \(S\) 时候的方案数,则:
尝试为其编一个组合意义。等价于 \(m\) 个球和 \(n\) 个盒子,问前 \(S\) 个盒子至少有 \(\lfloor\frac{m}2\rfloor+1\) 个球的方案数。这个东西即为 \(f_{S-1}\) 加上第 \(\lfloor\frac{m}2\rfloor+1\) 个球恰好落在第 \(S\) 个盒子的方案数,实际上就是把球在变盒子在变的情况转化成了只有球在变。对后者插板得到:
这样可以解决 \(m\) 是奇数的情况。\(m\) 是偶数的情况较此复杂许多。当点权均为正数时重心至多有两个,但是为非负数时重心可能有许多个,这些重心都在一条链上且链上非端点挂着的子树大小均为 \(0\)。由此可以有一个非常睿智的做法,枚举重心所在的链,我们需要做的就是令一个子树(或者子树补)的大小为 \(\lfloor\frac m2\rfloor\) 且这个子树为如此的极小子树,仿照上文减去子树根的各个子树合法的方案数即可。时间复杂度 \(O(n^2)\)。
继续做下去显然是要对于 \(u\) 统计以其为最小值的重心链有多少。相当于一个连通块,询问跨过 \(u\) 的重心链有多少。上面的做法貌似难以推广,因为我们在计算链的时候用到的是端点在某个方向上的信息(删去一个子树后的信息),这些方向好像并不好维护。我们的目光不要如此狭隘,考虑与连通块相连的不能经过的点,我们对那些点是否在重心链上做容斥!因为重心链上最多有两个这样的点,所以容斥是可以做的。这样每个点的方向都是确定的,同时可以并查集动态维护。此时不必要求上文中子树极小之类的限制。时间复杂度 \(O(n\log n+m)\)。
具体而言,并查集上维护周围不能经过的点在与并查集不同方向上子树大小恰为 \(\frac m2\) 的方案数之和,此时统计答案时做的容斥即为这个和与 \(i\) 在某一方向上子树大小恰为 \(\frac m2\) 的方案数乘积,同时还有不同连通块之间方案数之和的乘积,这些枚举周围的连通块后都不难求出,合并的时候更新方案数之和即可。
黄金之心
字符集大小 \(\sigma\),询问长度为 \(n\) 且不存在长为 \(k\) 的回文子串的个数。\(\sigma\le10^9+7,n\le1000,k\le25\)。
直接的想法是记录后 \(k\) 位的等价类信息做 dp,这样的复杂度和贝尔数相关。看上去不记录后 \(k\) 位的等价类信息是没法做的,而瓶颈在于状态太多。考虑用容斥减去一些状态,钦定 \(x\) 个回文子串,我们惊人地发现此时无需钦定每个等价类的代表字符不同。因为我们只需要根据回文结构确定出一些必须相同的等价类进行合并即可。此时的状态数就只有 \(9\times10^4\)。考虑如何搜出所有状态,将每个得到的状态后面复合上一个回文结构即可。
QOJ8780 Training,Round 2
直接 dp 是三次方,注意到一个状态被到达以后都能到达,于是值域定义域互换,每个横坐标对应的都是纵坐标的一段前缀。
Network_Error 发表了重要言论,上述做法是假的。
正常的做法是每次相当于操纵一个矩形中的点进行更新。于是可以构造使得每次操作的都是一个点,然后就是假的了。
[ARC093F] Dark Horse
注意到问题等价于将 \(2^n-1\) 个人分成若干组,要求每组的最小值 \(\notin A\)。直接 dp 没什么好的做法,对其容斥,统计 \(f_S\) 代表钦定 \(S\) 这个集合内的组的最小值 \(\in A\)。只需求出 \(f_S\) 即可。令 \(f_{i,S}\) 代表考虑完 \(A\) 中的前 \(i\) 大,\(S\) 被钦定且已经被填好的方案数,转移讨论一下是否钦定 \(A_i\) 即可。
代码源 day3t1.叮叮当当荡荡丁丁猩猩在攀爬
来代码源还是能过题的,被这道题送到了极其高的排名。
直接 dp 有一个 \(O(n^3)\) 的做法,不过完全不能进一步。考虑特殊性质中只有黑色点的限制,这是经典的反悔贪心。每个限制等同于一段前缀至多能选 \(x\) 个点,出于奇怪的原因变成全选上后要求至少要删 \(x\) 个点。
加上白色点的限制后相当于多了对后缀的限制,前后缀都有限制非常不像能做的样子,不过注意到如果能做的话大概是 \(O(n^2)\) 的。于是我们钦定删去点的总数后将对后缀的限制变成前缀最多选多少个。立马有一个看上去非常有道理的反悔贪心是扫描序列,选择能选的最小点。直接做就可以 \(O(n^3)\) 了。用线段树维护一下就是 \(O(n^2\log n)\) 了。感受一下随着能删的点越来越多,会发生的变化就是前缀的上界越来越大,猜测一下是凸的,实际上确实是,时间复杂度 \(O(n\log^2 n)\)。
UNR day1t1 星图
场上两个小时切了,题解不说人话,来一点人类做法。
先来考察一些必要条件,首先奇数位置必须为 \(1\),\(s_2\) 必然为 \(0\)。定义边重心是一条边 \(e\),使得删去 \(e\) 后剩下的两个子树大小的较小值在所有边中最大,设较小的那一棵子树大小为 \(x\),不难得到另外一个必要条件是 \(s_{2x+1\sim n}=1\)。我们尽可能地简化问题,不妨钦定移除的边只能为边重心,即其它边无法移除后使得两个子树点亮的点数量相等。这样钦定过后可以得到一些有道理的构造,不过这些构造都会被边重心左右各接一条链,链的末尾再接一些子树卡掉。根本原因在于链上的点可以随意分配到两个子树中,作为它们点亮的点的一部分。
不解决这个问题继续构造下去没有什么前途,索性用形式语言刻画一下,设链上点亮了 \(z\) 个点,链末尾较小的那个子树点亮了 \(x\) 个点 ,较大那个子树点亮了 \(y\) 个点。则 \(x+z\ge y\) 可以作为合法的充要条件(此处需要保证子树内部无法断边使得合法,这是较为简单的)。每次操作即为选择一个没有达到上限的 \(xyz\) 加一。类似前面的构造,我们想一直保证 \(0\le y-(x+z)\le 2\),这在奇数和偶数位置上微调一下即可保证,因此我们有了大体的构造方法,同时得到了另一个必要条件 \(s_{2y+1\sim n}=1\)。
接下来的构造就顺理成章了,找出 \(xyz\) 对应的点集之后,我们在子树内部始终以 bfs 序的顺序点亮,这样能保证子树内部不会有移除的边(其实这个结论的证明还需要基于边重心的性质)。时间复杂度 \(O(n)\)。
UNR day1t2 欢迎来到最前线
场上过了 \(50\) 分,已经把比较牛的部分想出来了,最牛的部分没想出来。
我们将所有点扔到数轴上,考虑匹配长什么样子。将所有参加匹配的点标上记号,最终的匹配方式一定是相邻匹配,进一步可以得到结论,对于某个颜色的一个极长连续段,一定是某个前缀作为正数,某个后缀作为负数参与匹配,否则调整一下不劣。考虑这个前缀到底有多长,显然是长到恰好匹配完前面所有没匹配的点为止,有结论,这个前缀所参与的匹配一定是一个连续段,其中黑色和白色点的数量相等,证明不需要任何脑子。
然后就有一个 \(O(n^2)\) 的 dp 了,找出折线图中上一个和它纵坐标相同的点转移即可。实际上这个匹配在折线图上还是有点畸形,考虑重新画一张比较好看的图,若当前点和上一个点不同颜色则在同一层,否则若为红色则在上一层,蓝色则在下一层。此时匹配就是在同一层中选择两个点,然后将中间这段连续段匹配。我们放宽限制,不要求中间连续段匹配,只要求在同一层中选择两个点匹配,可以发现这等价于我们将匹配方式扩宽到了相交和包含,但是由于这两种一定更劣,所以无需担心。
此时对于每层就能求出 \(f_k\) 代表匹配 \(i\) 对点的最小代价。然后对于每一层做一个 \((\min,+)\) 卷积即可得到答案,感受到 \(f\) 是凸的,闵可夫斯基和直接合并即可!!!
P8329 树
比较牛的部分没想出来,最牛的部分想出来了。
先写出多项式做法,必然要按照某种方式进行 dp。以 \(1\sim n\) 的顺序进行 dp,每次加入一个点后,在第一棵树上这个点必须接在某个点的下面,在第二棵树上可以接若干个点。令 \(f_{i,j,k}\) 代表加入了 \(1\sim i\),第一棵树上有 \(j\) 个叶子,第二棵树上有 \(k\) 个点没有父亲,加入 \(i\) 时考虑它在哪棵树上是叶子,这种钦定在第二棵树上是叶子的时候是毫无问题的,但是在第一棵树上是叶子时无法保证其确为叶子。
记 \(f_{i,j,l,k}\) 代表加入 \(1\sim i\),第一棵树上有 \(j\) 个被钦定为叶子的叶子,\(l\) 个没被钦定为叶子的叶子,第二棵树上有 \(k\) 个点没有父亲。时间复杂度 \(O(n^5)\)。
当钦定了 \(i\) 在第一棵树上是叶子时:
钦定了 \(i\) 在第二棵树上是叶子 时:
看上去就非常要容斥。写出这个容斥的形式:
括号里面有两个量,不过这两个量互异。拆这个式子的方向很多,考虑暴力的 dp 中我们被迫加了一维 \(l\) 来记录“没被钦定为叶子的叶子”,那么自然的想法就是容斥的过程中去掉这一维:
这样在 dp 的过程中每个点有三个选项。去掉了 \(l\) 那一维,同时 \(Q_i\) 是极其容易满足的。令 \(f_{i,j,k}\) 代表加入 \(1\sim i\),第一棵树中钦定了 \(i\) 个点为叶子,第二棵树中有 \(k\) 个子树的方案数。发现尽管第二棵树中让一个点为叶子可以直接满足,但是合并子树需要平方的做法。我们想将两者平衡一下。需要找到一种快速正着生成第二棵树的方式,为每个点找儿子是困难的,不妨为每个点找父亲,记 \(f_{i,j,k}\) 代表加入了 \(1\sim i\),第一棵树中钦定了 \([1,i]\) 中的 \(j\) 个点没有任何限制,第二棵树中钦定了 \((i,n]\) 中的 \(k\) 个点没有任何限制,第二棵树中 \([1,i)\) 中的每个点都已经找好了父亲的方案数。转移的时候考虑上一个点的父亲是什么即可。时间复杂度 \(O(n^3)\)。
CF917D Stranger Trees
比上一道简单很多。
第一步肯定是二项式反演转成钦定。那么每个连通块内部可以随意连,用 prufer 序列可以直接得到式子,和每个连通块大小乘积和连通块数量相关,这可以直接在树上 dp。
QOJ8528 Chords
区间 dp,\(f_{i,j}\) 代表 \([i,j]\) 能选出多少条边,然后数据随机,值域定义域互换。
P6326 Shopping
强而有力的。
树上依赖背包,但是基于值域,直接用树上背包是 \(O(nm^2)\) 的。考虑选的是一个连通块有没有什么好刻画的方式,按照 dfn 顺序 dp,如果当前点不选就直接跳到当前子树外面去,刷表转移即可。注意这个树上依赖背包需要多做一个点分治才能做原题。
单调队列优化多重背包,sshwy 误人不浅,后面忘了:
考虑一般的转移:\(f'_{j}=\max\limits_{k}(f_{j-kw_i}+kv_i)\),显然 \(f'_{j}\) 一定是从和 \(j\) 模 \(w_i\) 下同余的 \(f_{j-kw_i}\) 转移过来的,对于每个同余类分别转移。此时转移就是 \(f'_{j+kw_i}=\max\limits_{k'\leq k}(f_{j+k'w_i}+(k-k')v_i)\),后面的 \((k-k')v_i\) 显然可以拆,然后将 \(kv_i\) 放到外面。单调队列可以直接优化。时间复杂度 \(O(nm)\)。
为数不多的代码
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define all(x) (x).begin(),(x).end()
#define SZ(x) (x).size()
#define debug(...) fprintf(stderr,##__VA_ARGS__)
template<typename T>
void read(T &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
std::stack<char>st;
template<typename T>
void print(T x){
if(x==0) putchar('0');
if(x<0) putchar('-'),x=-x;
while(st.size()) st.pop();
while(x) st.push((char)('0'+x%10)),x/=10;
while(st.size()) putchar(st.top()),st.pop();
}
template<typename T>
void printsp(T x){
print(x),putchar(' ');
}
template<typename T>
void println(T x){
print(x),putchar('\n');
}
template<typename T,typename I>
bool chkmin(T &a,I b){
if(a>b) return a=b,1;
return 0;
}
template<typename T,typename I>
bool chkmax(T &a,I b){
if(a<b) return a=b,1;
return 0;
}
template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){
vec[u].push_back(v);
}
template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){
vec[u].push_back({v,w});
}
template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){
addedge(vec,u,v),addedge(vec,v,u);
}
template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){
addedge(vec,u,v,w),addedge(vec,v,u,w);
}
bool Mbe;
const int inf=1e18,MOD1=998244353,MOD2=1e9+7,iinf=1e9;
const int maxn=510,maxm=4010;
int f[maxn][maxm],g[maxn][maxm],w[maxn],c[maxn],dfn[maxn],d[maxn],fa[maxn],cnt,n,m,T,fdfn[maxn],vis[maxn],h,mx,sz[maxn],ans;
vint a[maxn];
void dfs(int p){
dfn[++cnt]=p;
fdfn[p]=cnt;
sz[p]=1;
for(int i:a[p]){
if(vis[i]||i==fa[p]) continue;
fa[i]=p;
dfs(i);
sz[p]+=sz[i];
}
}
void idfs(int p){
sz[p]=1;
for(int i:a[p]){
if(vis[i]||i==fa[p]) continue;
fa[i]=p;
idfs(i);
sz[p]+=sz[i];
}
}
void geth(int p,int g){
int rmx=0;
for(int i:a[p]) if((!vis[i])&&i!=fa[p]) chkmax(rmx,sz[i]);
if(chkmin(mx,std::max(g,rmx))) h=p;
for(int i:a[p]){
if(vis[i]||i==fa[p]) continue;
geth(i,g+sz[p]-sz[i]);
}
}
struct deque{
int hd,tl;
pii s[maxm*2];
void clear(){
hd=1,tl=0;
}
void push(int x,int t){
while(tl>=hd&&s[tl].fi<=x) tl--;
s[++tl]={x,t};
}
int size(){
return tl-hd+1;
}
void pop(int tim){
while(tl>=hd&&s[hd].se<tim) hd++;
}
int top(){
if(!size()) return -inf;
return s[hd].fi;
}
}dq;
void add(int r1,int r2,int num,int v,int w){//r1 -> r2 with (num,v,w)
// debug("r1 %lld r2=%lld\n",r1,r2);
for(int i=0;i<w&&i<=m;i++){
dq.clear();
int coef=0;
for(int j=i;j<=m;j+=w){
coef++;
dq.pop(coef-num);
chkmax(f[r2][j],dq.top()+coef*v);
dq.push(f[r1][j]-coef*v,coef);
}
}
}
void solve(int p){
// debug("p=%lld\n",p);
h=0,mx=inf;
fa[p]=0;
idfs(p);
geth(p,0);
p=h;
fa[p]=0;
cnt=0;
dfs(p);
for(int i=0;i<=cnt+1;i++) for(int j=0;j<=m;j++) f[i][j]=-inf;
f[1][0]=0;
for(int i=1;i<=cnt;i++){
int id=dfn[i];
add(i,i+1,d[id],w[id],c[id]);
for(int j=0;j<=m;j++) chkmax(f[i+sz[id]][j],f[i][j]);
}
for(int i=0;i<=m;i++) chkmax(ans,f[cnt+1][i]);
vis[p]=1;
for(int i:a[p]) if(!vis[i]) solve(i);
}
bool Men;
signed main(){
// freopen("extra.in","r",stdin);
debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
read(T);
while(T--){
read(n),read(m);
for(int i=1;i<=n;i++) read(w[i]),a[i].clear(),vis[i]=0;
for(int i=1;i<=n;i++) read(c[i]);
for(int i=1;i<=n;i++) read(d[i]);
for(int i=1;i<n;i++){
int u,v;
read(u),read(v);
addd(a,u,v);
}
ans=0;
solve(1);
println(ans);
}
debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
BZOJ3591 最长上升子序列
为啥想不到 ddp 来着。众所周知求 LIS 有一个二分的方法,这里 ddp 内部记录那个数组的状态即可。
ARC153D Sum of Sum of Digits
唯一一个正常题。其它全都不是题。
\(f_{i,S}\) 代表考虑后 \(i\) 位,产生进位的位置为 \(S\),后 \(i\) 位的贡献及其对应的 \(x\)。问题在于产生进位的位置非常没有规律性。实际上注意到进位等价于 \(x\) 的后 \(i\) 位加上 \(a\) 的后 \(i\) 位超过 \(10^i\),那么将 \(a\) 按照后 \(i\) 位排序后,进位的位置就是一个后缀。
P3959
平安。
HDU6984
魔怔题。拥有 \(O(1.618^{\sqrt{2n}})\) 的高超复杂度。
首先一个直接的做法是 \(O(2^k\times n)\),然后按照等价类填可以做到 \(O(4^{\frac nk}\times n)\),平衡一下得到 \(k=\sqrt{2n}\)。但是注意到后者做法中状态数是和斐波那契数同阶的!
ARC085F
做法很多,但是找到最简单的好像不太容易。