可持久化非确定状态AC自动分块维护线段平衡仙人掌优化最小费用最大流预处理混合图上莫比乌斯反演莫队带花舞蹈链并查集树状数组套主席树预处理动态DP分治FFT求多项式逆元对数函数的指数函数用可持久化并查集合并最小费用循环流上插头DP
这种类型的 dp 的特点就是大部分转移形如 \(f(i,j)\rightarrow f(i+1,j+1)\) 之类的,并且当以上转移出现时原数组被清空,这就可以用一个 deque
来维护,然后对于全局赋值/全局加,需要对每个位置维护一个时间戳,并记录上一次赋值/加是什么时候,以便标记下传。
(貌似可以用其他方式迅速计算的式子都可以变成一个简单的 dp 形式,然后用以上的方法维护?)
题目阴间的条件 \(i-w_i<m\)(其中 \(w_i\) 为前 \(i\) 个数的 mex)应该要想到换元 \(c_i=i-w_i\),那么 \(c_i<m\) 的形式显然会更适合 dp 以及后期的 dp 优化。接下来就是思考对于一个固定的序列 \(c_i\) 如何计算有几种符合条件的 \(p_i\)。
发现 \(p_i\) 的计数仅与 \(c_{i+1}\neq c_i+1\) 是哪些 \(i\) 有关,所以将它们设元 \(Y_i\)。对于 \(Y_1\le Y_2\ge Y_3\le Y_4\ge Y_5\le\dots\) 这样的形式,将所有小于等于号容斥成大于号应该是一个重要的思想。
所有 \(f(i,j)\rightarrow f(i+1,j')\) 且满足 \(j'-j\) 很小的转移都是可以考虑转化成多项式或者矩阵然后分治乘解决的。
P.S.:回来看这题的时候看到洛谷最后一篇题解写得很好,和 mex 相关的问题采取删数而不是加数的方式是好的。确实,记 \(f_{i,j}\) 为前 \(i\) 个位置上面浮着 \(j\) 个数,那显然可以转移到 \(j-1\) 或任意 \(k\ge j\),贡献很好算。不用记录在 mex 中的数的个数,因为可以视为是从 \(-\infty\) 连到当前 mex 为止的,不合法的 \(k\ge j\) 对应于删掉了一个 \(<0\) 的数,自然不合法(不合法就是最后 \(i=0\) 时会有 \(>0\) 个浮在 mex 上面)
二维平面应该只有两种办法:一种是扫右端点维护左端点,一种是猫树。
后者直接写出来会发现是两只 \(\log\),但是因为某种原因我们发现答案的下界是 \(2(\max(W,H)+1)\),所以最优矩形一定会跨越 \(x\) 轴中点或者 \(y\) 轴中点。于是猫树只用一层。
(这样用答案下界来限制算法的题目很少见啊)
简要题意:\(Q\) 次操作,每次操作可以加入平面上一个带权 \(w\) 的点 \((x,y)\) 或者查询所有“\(x\) 坐标不为 \(x_0\) 且 \(y\) 坐标不为 \(y_0\) 的点”的点权最大值。\(Q\le 10^6\),值域 \(10^9\),空间 4MB,时限 1s。
想到 KDTree,过不了。想到把平面分成 4 部分递归下去,需要值域线段树,空间 \(\log\),过不了。感觉蠢完了。
尽管是一道很蠢的题,我们还是要记住只保留有用节点的思想。什么是有用节点呢?如果一个节点被别人偏序了,或者被几个人一起偏序了,那它就无用了。
在这道题里,什么是偏序呢?对于若干个点,它们能够覆盖平面上的一个点集。如果一个点自己能覆盖的区域是比它大的点所覆盖的区域的子集,那它就没用了。否则它一定会使得这个覆盖区域的子集缩小。
然后发现这个覆盖区域只有以下几种情况:空集,除去一个十字,除去一行,除去一列,除去两个点,除去一个点,全集。
于是改变次数是 \(O(1)\) 的,有用点的个数也是 \(O(1)\) 的,直接维护即可。空间是 \(O(1)\) 的,时间是线性的。
简要题意:给定正整数序列 \(a\),每次操作可以给 \(a\) 的某个元素 \(+1\),求最小操作次数使得 \(a\) 中所有数异或和为 \(0\)。\(n\le 100\),值域 \(10^9\)。
大体思路:对于序列中一个数,每次加一最后会导致末尾出现一堆 \(0\),而联想到若干个数的异或和 \(\le\) 这些数的和,所以可以结合问题中的“异或”导出有用性质。
简要题意:给定一棵树,每个点对其相邻的点有一个排序,初始每个点的指针指向其第一个元素。接下来从根节点出发,每次走一步,走出去之后将指针循环后移一格。多次询问 \(k\) 步之后到达那个节点。
题目特点:从一个初始状态开始不断操作,多次询问 \(K\) 步之后到达的点。
见到另外一道题,题目特点完全一样。那道题是用平衡树维护所有询问,每次访问到一个节点时把询问往下推。这道题不一样。究其原因大概是那题是 DAG,整体信息难以维护,而这题是树,有更多好的性质吧。
一开始想这道题的时候陷入了之前那道题的思路中,求每个子树内会消耗多少的字典序。但是经过思考发现第几次经过这个点会对其消耗的字典序量产生影响,这就很难做了。
以上的做法应该属于从局部思考,正解是从整体思考。事实上后者会很简单:如果每个点最后指向父亲,那就是走整棵树的欧拉序;现在就是先走前若干个节点的欧拉序,再走更多个节点的欧拉序。最后可以做到线性。
关键应该在于从整体思考问题。
简要题意:给定一棵有根树,每个节点有若干个棋子,双方平等博弈,每步可以选一个节点,将其任意个棋子挪向它的某一个儿子。问谁赢。
解锁技能:阶梯 Nim
阶梯 Nim 的原型就是在一个台阶上玩 Nim 游戏,每次可以将一个台阶上的任意个石子下移一个台阶,移到地上就不能移了。
阶梯 Nim 的结论是等价于拿出所有奇数台阶上的石子玩普通 Nim。证明很简单:偶数阶上的石子可以扔掉,因为对于一个胜者来说,如果对方移了偶数阶的石子,那他可以立即将这些石子再移回偶数阶(注意,这里就是奇数阶和偶数阶不对称的地方,因为 \(0\) 是偶数),从而保持胜局,所以只考虑奇数阶上的石子,就是普通的 Nim 了。
知道这个结论之后这题就是板子了。给每个奇深度的叶子节点多挂一个叶子之后就是树上的阶梯 Nim,直接取出奇深度的异或起来即可。
博弈论的主要三条思路变成了四条:SG 函数,决策覆盖,朴素决策,保持胜局(或决策抵消)。保持胜局的意思就是已经赢了的人可以消除掉不必要的影响因素。注意到在公平游戏里面不管谁赢了都会去消掉它,那这个影响因素就等于不存在了。
简要题意:给定一棵有根树,初始所有节点都是白色,每次进行三种操作中的一种:
- 选择一个点,把它往下 dfs 所有见到的第一个白色节点染黑
- 把一个点的所有子树染白
- 询问一个点的颜色
\(n,Q\le 10^5\)。
点击查看题解
首先第一感当然是暴力操作看看复杂度对不对,但由于有第 2 种操作撤销复杂度显然是不对的。
这时候我们就面临一个问题:操作 1 是一个复杂的操作,它会影响很多互不相干的点。怎么解决这个“影响很多互不相干的点”成为这题的关键。
(一开始自己的思路是对每个点维护操作序列,但是比较繁杂,应该最多只能做到根号,所以即使有一个不错的转化也要记得跳出来换换思路试试)
思路一:树上问题,修改操作复杂但易于离线统一处理,查询操作较简单,考虑操作分块。
将操作每 \(B\) 个分成一块,每块内将所涉及到的所有点拿去建虚树,然后每个修改、查询在虚树上暴力进行,整个块处理完以后把这个块的修改拍回到整棵树上去。
询问分块的应用瓶颈在于:1. 需要有较好的方式将整个块的修改拍回到原树上 2. 修改和查询操作只和链/子树相关
前者“拍到原树上”的过程我们只要求复杂度做到 \(O(n+B^2)\) 即可。
本题中记录下来虚树上每条边有几个黑点以及每个点子树内是否清空过,整块结束后 dfs 一遍整棵树即可。复杂度 \(O(n\sqrt n)\)。
思路二:修改操作复杂但查询操作简单,将算法向查询倾斜。
一个体现这种思路的方式是:对于每个查询,我们寻找对它产生影响的那个修改是哪个。(对于一般的题目,我们是对于每个修改,找到它影响到的点并影响它们)
这样找就可以想到如果一个 \(x\) 处的修改会影响到 \(y\),那么说明 \(x\) 到 \(y\) 路径上的操作 1 数量 \(\ge\) \(x\) 到 \(y\) 的距离。这样我们就能想到线段树上二分找到后缀最大值是否 \(\ge 0\)。
然后考虑操作 2,我们要消除一个子树内产生过的所有影响,也就是使得子树内所有点的后缀最大值都归为 \(-1\)。这样就是子树内赋值为 \(-1\),然后将点 \(x\) 的权值减去“当前后缀最大值+1”即可。复杂度 \(O(n\log^2 n)\)。
简要题意:对于值域 \([1,n]\) 的序列 \(a\),称其合法当且仅当可以将每个 \(a_i\) 加上一个非负整数使之变为排列,令其权值为所有 \(a\) 中所有颜色出现次数的 \(k\) 次方和。求所有合法序列的权值和,模 \(998244353\)。\(n\le 10^9,k\le 10^5\)。
点击查看题解
(把它转到网格上走路的想法是彻底失败的,再说一遍,要尝试多条路子)
一个很经典的问题。
有一条长为 \(n\) 的路和 \(n\) 个人,每个人要停车到 \(a_i\),如果被占了就往后找第一个没被占的停,求每个人都能停下的概率。
转化:有一个长为 \(n+1\) 的环和 \(n\) 个人,每个人要停车到 \(a_i\),如果被占了就往后找第一个没被占的停,求没人在 \(n+1\) 停的概率。
显然最后每个位置被空出来的概率相同。于是任意一种合法方案可以映射到 \(n\) 个不合法的方案,概率为 \(1\over n+1\)。
在这道题里面,我们关心的只是每种颜色出现的次数,而上面这个映射是不改变每种颜色的出现次数的。所以求出长为 \(n\) 的每个位置可以选 \([1,n+1]\) 的数列的答案,最后乘上 \(1\over n+1\) 即可。
答案就是 \(\sum\limits_i \binom{n}{i}i^kn^{n-i}\),这个可以用斯特林数硬推,也可以用 EI 的 Binomial Sum 的技巧。详见 这里 和 这里。
复杂度 \(O(k\log k+\log n)\) 或 \(O(k+\log n)\)。关键在于前面这个转化,太经典了。
简要题意:有 \(n\) 个公司,每个公司有至多一个父公司,而父公司一定没有父公司。每轮每次随两个没有父公司的公司 \(A\) 和 \(B\),让 \(A\) 的父公司为 \(B\),而 \(A\) 的所有子公司全部自由掉。求使得只有一个公司没有父公司的期望轮数。\(n\le 10^6\)。
鞅与停时定理模板。拿去讲题用。
简要题意:Alice 和 Bob 玩一个字符串集合 \(S\),轮流选出 \(S\) 中一个串,删掉其中所有某个字母并把用其分割所剩下的串加入回 \(S\),不能操作者输。给定一个字符串 \(s\),每次问 \(s\) 的一个子串谁赢。\(n\le 10^5,|\Sigma|=26\)。
点击查看题解
发现所有有用区间是每个点向左或向右遇到的第一个字母 \(c\) 所组成的区间,一共 \(O(n|\Sigma|)\) 个。直接暴力即可。
注意一个技巧:不要用 map
存所有有用区间,而是考虑找有用区间的算法流程,以便分层。例如这里记录 vL[N][26]
和 vR[N][26]
会好很多。
简要题意:给定 \(m\) 条 taxi 的有向历史路线,判断 taxi 是不是博特开的。taxi 是博特开的当且仅当对于任意点 \(a,b\),从 \(a\) 到 \(b\) 所经过的路径一定相同。\(n,m\le 3\times 10^5\)。
点击查看题解
(想了 1h 的 \(polylog\) 做法啊啊啊)
(包括考虑了两条路径之间什么时候合法,对每条路径 CDQ 分治成左边到右边一定经过中间(这个结论远弱于下面第一个结论吧))
首先一步转化是等价于对于所有 \(A\) 到 \(B\) 的路径,路径上第二个点 \(C\) 都相同。(这个没想到)
变成这样后固定 \(B\) 就很好枚举 \(A\) 判断是否合法了。剩下就是一个大小分治的事儿。
简要题意:\(200\times 200\) 的网格里有一个矩形,你可以问 \(4\) 次点集,交互库返回矩形中有点集中的几个点。要求这个矩形的周长。
小清新交互,拿去讲题。
简要题意:分解 \(2^{1024}\) 级别的大数,交互库提供加减乘除次幂以及开方。
小清新数论,拿去讲题。
简要题意:给定一个 \(n\times m\) 网格,格子中填有 \(1\sim n\times m\) 的互不相同的权值。称一个区间 \([l,r]\) 合法当且仅当权值在 \([l,r]\) 内的格子形成一棵树。求有几个合法区间。\(n\times m\le 2\times 10^5\)。
见洛谷题解。
简要题意:令集合幂级数 \(F_i(t)=xt^{a_i}+yt^{b_i}+zt^{c_i}\),求 \(\prod F_i(t)\),乘法为 \(XOR\) 卷积。\(n\le 10^5\),值域 \(2^{17}\)。
点击查看题解
很厉害的一道 FWT 题和解方程题。以下定义 \(S\odot T=[2\nmid |S\cap T|]\)。
首先按照剧本先把 FWT 式写出来:\(f_{i,S}=(-1)^{S\odot a_i}x+(-1)^{S\odot b_i}y+(-1)^{S\odot c_i}z\)。
要想办法用好 \(x,y,z\) 预先给定的性质,容易发现每个 \(f_{i,S}\) 一定形如 \(\pm x\pm y\pm z\)。为了简化问题,我们直接令 \(c_i=0\),那剩下的就是 \(z\pm x\pm y\) 了,只有 \(4\) 中情况,而我们关心的是每一位 \(S\) 来说 \(f_{i,S}\) 的乘积,所以对于每一位 \(S\),我们只关心 \(f_{*,S}\) 取到了 \(c_1\) 个 \(z+x+y\),\(c_2\) 个 \(z+x-y\),\(c_3\) 个 \(z-x+y\),\(c_4\) 个 \(z-x-y\)。
接下来的一个思想很重要:我们要尝试通过我们手里有的算法,用这些算法的结果构造出一些关于 \(c_1,c_2,c_3,c_4\) 的方程,进而把它们解出来。
我们有什么工具呢?我们手上最好的工具就是 FWT,考虑构造几个 FWT 出来。但是注意我们不能对 \(n\) 个三元组都构造一个 FWT,所以我们只能每个三元组选一个,组成一个幂级数进行 FWT。
如果每个三元组选出一个 \(a_i\),那 FWT 完得到的结果是 \(c_1+c_2-c_3-c_4\),查上面几个 \(c\) 中 \(x\) 的系数可知。
如果每个三元组选出一个 \(b_i\),那 FWT 完得到的结果是 \(c_1-c_2+c_3-c_4\)。
技穷了?考虑整点花的。注意到 \((-1)^{S\odot a}(-1)^{S\odot b}=(-1)^{S\odot(a\oplus b}\),如果我们每个三元组选出 \(a_i\oplus b_io\),那 FWT 完得到的结果是 \(c_1-c_2-c_3+c_4\),对应于 \(x\) 和 \(y\) 的系数相乘。
真的技穷了?别忘了最基本的 \(c_1+c_2+c_3+c_4=n\)。
\(4\) 个方程把 \(4\) 个变量解出来即可。解出来之后快速幂即可。
事实上这个 \(x,y,z\) 可以扩展到一般的 \(m\) 个 \(x_i\) 的情况,参见Alex_Wei 巨佬的博客。
事实上,\(x_i,y_i,z_i\),咳咳。
简要题意:交互库有 \(n\) 行球,每行球有 \(L\) 个,标号在 \([1,10^{18}]\),现在要从每一行中选出标号连续的至少 \(L/n\) 个球,使得任意两行之间的区间不相交。每次可以询问一行的一个前缀有几个球。\(n\le 1000,L\le 10^{18},n|L\),询问次数 \(2\times 10^5\)。
点击查看题解
脑子不清醒。
考虑一定要找个什么东西分治下去。一开始想着冲着值域分治下去,发现大失败。
正确方式是冲着值域分治下去,把每行的第 \(L/2\) 个球按标号排序,那么前 \(n/2\) 行递归值域到左边,后 \(n/2\) 行递归到值域右边即可。
每次手写 nth_element
找中位数即可。注意有重复元素,第二关键字是标号。
简要题意:给定一个 DAG,每个点上有 \(a_i\) 个球,每次可以选一个节点,取走任意个球,然后将它的出边指向的节点的球数变为任意值(注意不必须减少)。求谁赢。\(n,m\le 2\times 10^5\),值域 \(10^9\)。
点击查看题解
当没有边的时候就是传统 Nim 游戏,所以这个应该强于传统 Nim 游戏。这一点是注意到了。
然后手玩了一堆有向图也没有得出什么结果。其实主要原因是没有朝对的方向玩。
以后看到这种题除了想“几个局面互相独立”还应该想到 Mex。
原来一个点的 \(\omega\) 的指数是它的所有出边的 \(\omega\) 的 Mex。
猜想每个次数的 Mex 可以分别取异或是对的。
简要题意:给定序列 \(a\),每次可以将一种颜色全部变成另一种颜色,代价为该颜色个数,定义总代价为使得 \(a\) 中任意两种颜色出现区间不交的最小代价和。\(Q\) 次单点改并询问总代价。\(n,Q\le 2\times 10^5\)。
点击查看代码
前面都想到了,直到变成区间加减查 \(0\) 分成的段的众数出现次数之和都想到了。然后就去想分块了。还真给我想出来了/cf。
关键在于这里每一段的众数怎么算!如果是一般的序列就只能分块了!找性质!
由于查询的每个区间必然包含一种颜色完整的出现区间,所以把每种颜色的出现次数扔到左端点去!
剩下的都是 trivial 的。时间复杂度 \(O(n\log n)\)。
简要题意:有一个左右点数均为 \(n\) 的二分图,每条边有一个出现概率,求这个二分图存在完美匹配的概率。\(n\le 6\)。(Hard version 没意思)
点击查看题解
至今还没有学会蜜桃猫。
看到一共才 \(36\) 条边应该想到蜜桃猫的。
把 \(6\) 个右部点分成两半,对于每一半,考虑左边 \(6\) 个点到右边 \(3\) 个点的连边情况,我们只关心 \(6\) 个点中哪 \(3\) 个可以被完美匹配,发现只有 \(\binom 63=20\) 种可能,暴力用 \(2^{20}\) 的 mask 记下来,两边合并是一个 FMT,做完了。
P.S.
回来重新看的时候发现完全想歪了,直接冲着 Hall 定理就去了,然后一点思路都没有。是不是 Hall 定理只有在 \(n\) 很大的时候管用呢。
弱智 bitset
题,哪来的 *3200。拿去讲题。
简要题意:构造一个颜色序列 \(a\),初始所有位置都未点亮,每个时刻会点亮一个给定的位置 \(p_i\),要求在任意时刻,任意子段中,如果只考虑点亮的位置(忽略未点亮的位置),其中至少有一个独一无二的颜色。\(n\le 8500\),颜色数 \(\le 24\)。
点击查看题解
没用了,这么水的构造都不会。
注意到所有点都点亮的时候的最优解显然是 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
这样的东西,于是想着我们每次要找到一个全局中独一无二的元素,然后分成几半递归下去。这样就彻底陷入死胡同了,递归的子问题很不好看,或者说,压根不是子问题。
以上的思路是用“由寡及众”的思路去考虑的,即每次找到唯一特殊的元素,然后尝试把剩下的问题递归分成若干个互不相干的子问题。
正确的思路是“由众及寡”去考虑,也就是我们先想办法找到尽量多的互不相干的元素(可以视为是最后一层的子问题),把它们删掉,然后考虑剩下的东西。这样的好处是“剩下的东西”就没有“互不相干”这样奇怪的要求了。
(是不是可以认为“递归到子问题”形成一个树形结构,第一种思路是砍根,第二种思路是剥叶子?)
第一种思路对应于考虑 4
这个元素,第二种思路对应于考虑 1
这个元素。
考虑怎么定义“互不相干”,就是如果一个子段包含了其它颜色,那就由其它颜色保证唯一性;否则任意时刻不能只包含我这种颜色。这个直接每个时刻连两条边贪心即可,一定能选出至少 \(\lceil n/3 \rceil\) 个位置,颜色总数即为 \(\log_{3/2} n\),做完了。(这就是 \(24\) 这个神奇限制的来由)
简要题意:给定两棵树 \(T_1\) 和 \(T_2\),对 \(T_2\) 的每条边 \((x,y)\) 选择 \(T_1\) 上对应的路径 \((x,y)\) 上的一条边与之匹配,求方案。\(n\le 2.5\times 10^5\)。
点击查看题解
又是什么都想到了就没想到最后一步的一天。
首先拍个 Hall 定理上去发现无论如何一定有完美匹配。
我们希望:每次从 \(T_1\) 中和 \(T_2\) 中各拿出一条边配对,然后选两个点缩起来,递归到大小为 \(n-1\) 的子问题。
关键在于:1. 选哪两条边 2. 缩哪两个点。
首先我们肯定想剥叶子,剥 \(T_1\) 的叶子,找到 \(T_2\) 上连接叶子与其父亲的点,把它删掉。
然后想着是把叶子与其父亲缩起来,但是这样就需要 LCT 了。
正确的方式是把删掉的那条边的两个端点缩起来,这样就只用查询一条路径上第一个和 \(u\) 不在同一连通块的点就做完了。
怎么说呢,就是要换一个对象/方向考虑,有时候倒过来考虑,有时候拉出一个对称的对象考虑。
简单 bitset
高消题。拿去讲题。
简单倍增题。拿去讲题。但是我怎么想成点分治了呢,应该本质一样但是难写点。
简要题意:有 \(n\) 个人打牌,牌有 \(4\) 种花色(注意并不是所有花色的牌数都相同),现在每个人手上有 \(a_{i,j}\) 张花色 \(j\) 的牌,你手上有 \(b_j\) 张花色 \(j\) 的牌要发给他们,要求发完之后每个人的总牌数相同,定义一个人的得分为“他的手中最多的花色出现次数 - 别人手中最多的花色出现次数”与 \(0\) 取 \(\max\)。求发完牌后每个人的最大可能得分。\(n\le 5\times 10^4\)。
点击查看题解
啥都不会。不是,这题为什么会想到费用流啊。
想到钦定一个人拿一种花色最多然后尽量全给他,二分 \(mid\),其他人的花色数都 \(\le mid\) 了。
然后盯着这玩意发呆,有一个非常麻烦的限制是每个人拿到的牌数应当相同,加上要求每个花色最大出现次数 \(\le mid\) 的限制,还有每种花色总数不超过 \(b_i\),怎么看怎么阴间到家了。
可能这种奇奇怪怪的限制就适合转成网络流吧。直接建出图来就可以了。
最后一步是个很厉害的技巧:二分图最大流,其中一边点数很少,转成最小割。枚举左边 \(4\) 个点中割了哪几个,剩下的就是一堆 \(\min\) 加起来,贪心即可。
小清新交互题。拿去讲题。
简要题意:对于一个序列 \(a\),定义它的生成图为将所有满足 \(i<j\) 且 \(a_i<a_j\) 的 \((i,j)\) 间连一条无向边得到的图,定义它的权值为它的生成图的连通块个数。有 \(Q\) 次询问,每次单点修改,询问序列 \(a\) 的权值。\(n,Q\le 10^5\)。
关卡目标:做到 \(O(n\log n)\)。
点击查看题解
首先每个连通块形如一个区间,当且仅当左边比右边都大的时候断开。这都想到了。
现在的选择是经典的:扫时间,扫下标,还是扫值域。第一感是线段树分治,能做到 \(\log^2\),不提。
就说为什么正解的路认为不可达吧。扫时间,对于每个值,维护它出现的 \(10\) 数量以及它是否出现,查全局最小值出现次数即可。
想到这里没往下想的原因是没意识到我们只有维护 \(10\) 的数量而不是整棵线段树就可以知道阈值 \(v\) 是否形如 \(11\dots1100\dots00\) 的形式。如果对一个区间内的线段树进行区间修改肯定不可行,但是现在我们只用维护一个值,就随便做了。
简要题意:给定 \(n\) 个点的树,有 \(r\) 个关键点,\(Q\) 次询问,每次询问是否能从点 \(x\) 到达点 \(y\),其中每走 \(K\) 步就必须在某个关键点处歇脚,其中 \(K\) 为全局定值。
点击查看题解
胡了个奇怪做法,应该是对的,但是比正解复杂多了。
一个应该很典的“双向奔赴”技巧:两个点之间的距离 \(\le K\) 等价于以这两个点为圆心的半径为 \(K/2\) 的圆相交。(当 \(K\) 是奇数的时候就把点数翻倍)
那么这 \(r\) 个点两两之间的连通关系就可以由这 \(r\) 个圆之间是否相交确定。
而进一步地,我们就可以从每个点开始同时在树上 bfs 来连边。
每次询问同样是找到从 \(x\) 到 \(y\) 路径上第 \(K/2\) 的点,用同样的“双向奔赴”的分析可知我们只用关心那个点所处的连通块。就做完了。
不知道这个“双向奔赴”技巧在别的地方还有没有用到的。
耐心分讨题。
简要题意:对于一个每个格子为 \(0\) 或 \(1\) 的网格 \(a_{i,j}\),定义每个 \(1\) 四连通块的价值为 \(1+[该连通块不与外面连通]\)。给定数列 \(a\) 和 \(b\),\(Q\) 次询问一个值 \(x\),求 \([a_i+b_j>x]_{i,j}\) 的权值减去 \([a_i+b_j\le x]_{i,j}\) 的权值。
点击查看题解
我什么时候才能记清楚欧拉定理是 \(V-E+F\) 而不是 \(V+E-F\)。
使用欧拉定理:\(V-E+F=cnt\),其中 \(cnt\) 为连通块数,不包括最外面的无穷面。
仔细研究两种颜色形成的连通块,可以得到式子:
其中 \(out_1,out_2\) 为与最外面连通的连通块数,\(\square_1,\square_2\) 为四个相邻的格子形成的正方形数。
我们要求的是 \(2cnt_1-out_1-2cnt_2+out_2\),化简得 \((V_1-V_2)-(E_1-E_2)+(\square_1-\square_2)\),而这些量都是容易计算的,FFT 即可。时间复杂度 \(O(n\log n)\)。
看来一开始想的一行 \(0\) 一列 \(1\) 都跑偏了呢。是不是能拿去出题。
简要题意:有一个长为 \(n\) 的排列 \(a\),初始有 \(n\) 个集合 \(S_i=\{a_i\}\)。你可以进行 \(2.2\times 10^6\) 次操作,每次操作可以选两个值域不交的集合,新建一个集合为它们的并。目标是构造出给定的 \(Q\) 个 \(a\) 中的区间集合。\(n\le 2^{12},Q\le 2^{16}\)。
点击查看题解
有一个很显然的分块做法,这里说个更厉害的,是洛谷第一篇题解。
按值域建线段树,每个节点 \([l,r]\) 开一个 vector
记录值域 \([l,r]\) 内的点的位置。查询时暴力递归合并,显然复杂度不对,所以对每个区间的查询记忆化,很神奇地复杂度就对了。
为什么呢?对于一个长度为 \(len\) 的节点,它被访问的次数为 \(\min(len^2,Q)\)。 令 \(q=\log Q\),对于长度 \(\le 2^{q/2}\) 的节点,次数和为 \(\sum_{i\le q/2} 2^{\log n-i}{(2^i)^2\over 2}=O(2^{\log n+q/2})=O(n\sqrt Q)\);对于长度 \(\ge 2^{q/2}\) 的节点,只有 \(2^{\log n-q/2}\) 个,次数和为 \(Q2^{\log n-q/2}=O(n\sqrt Q)\)。
巨好写。
小清新 Hall 定理,拿去讲题。
简要题意:给定 \(n\times n\) 的网格,边界处权值给定,中间有一部分点是坏点,其它点需要你填入权值,最小化每对相邻非坏点的权值差的绝对值之和。\(n\le 200\)。
点击查看题解
被结论题创飞了。
考虑如果只有两种颜色的时候,这就是 CF1368H1 Breadboard Capacity,只是倒过来了,所以我们可以把问题变成最小割,然后直接转最大流做。
但是现在有多种颜色,所以考虑大小转 \(01\),但是怎么保证前一次最小割方案是后一次最小割方案的子集呢?
事实上有定理保证这一点:令 \(\mathcal{MC}(A,B)\) 为点集 \(A\) 和点集 \(B\) 之间的所有可能的最小割在 \(A\) 一边的点集。对于任意 \(U_1\subseteq \tilde U_1, \tilde U_2\subseteq U_2\),对于任意 \(W\in \mathcal{MC}(U_1,U_2),\tilde W\in \mathcal{MC}(\tilde U_1,\tilde U_2)\),有 \(W\cup \tilde W\in \mathcal{MC}(\tilde U_1,\tilde U_2)\)。
所以一定合法,我们只需要跑 \(O(n)\) 次最大流即可。复杂度不对,于是发现是每次把一个点从连 \(S\) 改成 \(T\),所以退流即可,由于每个点的流量为 \(O(1)\) 所以复杂度很对。总复杂度 \(O(n^3)\)。
简要题意:对于一个黑白点组成的环,定义它的权值为每次选两个同色点匹配,相交的边对数的最小值。对于一个带
?
的串 \(s\),定义它的权值为所有将?
改成黑或白之后的环的权值和。给定 \(s\),\(Q\) 次修改单点后查询 \(s\) 的权值。\(|s|,Q\le 2\times 10^5\)。
很有意思的转化,拿去讲题。
简要题意:有两个 01 串 \(a\) 和 \(b\),每次操作可以翻转一个含有 \(K\) 个 \(1\) 的区间,求是否能在 \(4n\) 步内使得 \(a=b\)。\(n\le 2\times 10^3\)。
点击查看题解
题解在这。关键在于想到考虑每两个 \(1\) 之间的 \(0\) 个数,然后导出不变量。
简要题意:平面上有 \(n\) 个整点 \((x_i,y_i)\),称一个三角形是合法的,当且仅当它的严格内部有奇数个点,且面积为整数。求有多少个由这些整点组成的三角形。\(n\le 6000\)。
点击查看题解
首先两个基础公式,第二个我硬是没想起来去用(
由 \(S\) 是整数推出 \(m\) 是偶数,由 \(n\) 是奇数呢?推出 \(S\) 和 \(m\over 2\) 的奇偶性相同。
然后就跑偏了,尝试用各种割补法刻画 \(S\),想把 \(S\) 的奇偶性摊到三个割补的三角形上,但是对于随后怎么算也毫无准备。
正确的想法是:暴力美学,枚举 \(x_1,y_1,x_2,y_2,x_3,y_3\) 模 \(4\) 得到的值。
其实 \(m\) 是很好刻画的,就是 \(\gcd(x_i-x_j,y_i-y_j)\)。
而我们只关心 \(m\bmod 4\) 的值,所以可能我们只用关心 \(x_i,y_i\) 模 \(4\) 的值?
其实并不是,\(\gcd(x,y)\bmod 4\neq \gcd(x\bmod 4,y\bmod 4)\),但是这个式子在 \(x,y\) 都是偶数的时候是成立的!
继续推,\(m\) 为偶数意味着三边是偶偶偶或者奇奇偶,所以至少有一条偶边,而偶边意味着上面那个式子成立,我们就确实只需关心 \(x_i,y_i\) 模 \(4\) 意义下的值!
所以枚举与那个偶边相对的点 \((X,Y)\),其它点只需要关心 \(x_i\bmod 4,y_i\bmod 4,\gcd(|x_i-X|,|y_i-X|)\bmod 4\) 就行了。暴力枚举点对即可。时间复杂度 \(O(n^2+4^6n)\)。
关键的没想到的一步是可以暴力枚举模 \(4\) 后的值。可能有时候性质不需要推太深,只需要推到常数项以内,剩下的由暴力解决。
简要题意:给定 \(n\) 个点的带权完全无向图,求最小生成树,满足对于 \(1\le i\le K\),点 \(i\) 的度数不超过 \(d_i\)。\(n\le 50,K\le 5\)。
点击查看题解
拟阵交板子。板子部分就不说了,看看不板的那一部分。
注意到这个度数限制并不直接是一个拟阵,例如考虑链 \(1 - 2 - 3 - 4\),每个点度数限制都是 \(1\),其中匹配 \(2-3\) 无法扩展成任何大小为 \(2\) 的匹配(是存在的,如 \(1-2,3-4\))。
所以我们进行一些独立性的转化。具体地,我们枚举前 \(K\) 个点之间的所有可能的连边状态,这样度数限制就只在于前 \(K\) 个点和后 \(n-K\) 个点之间了,这是一个标准的划分拟阵(Partition Matroid)。(我现在才发现)
剩下的限制只有一个生成树的限制了,就是图拟阵(Graph Matroid)。求拟阵交即可。
有一个很值得提一嘴的优化,就是对于后 \(n-K\) 个点之间的边,我们只用考虑它们的最小生成树上的边。这样拟阵元素个数是 \(O(nK)\) 的,就健康很多了。
一个和拟阵交相关的优化是封装的 Oracle 不要每次重新加一遍,而是进行一次 prepare
初始化,然后进行 \(n\) 次 predict
加入一个元素后是否破坏独立性。
简要题意:对于一个集合 \(S\),你每次可以选出 \(S\) 的一个非空子集并将这个子集替换成其 \(\mathrm{mex}\)。定义集合 \(S\) 的权值为对其进行任意次操作之后,使得 \(S\) 只剩下一个数,这个数的最大值。给定序列 \(a\),对 \(a\) 的每个前缀求其权值。\(n\le 2\times 10^5\)。
关卡目标:时间复杂度 \(O(n\log^2n)\)。
点击查看题解
被自己创死了。
想的方向就不是很对,前面一直在想类似于“给数 \(i\) 赋一个 \(2^{i-1}\) 的权值”之类的东西,但是解决不了大数无法拆分成小数的问题。于是开始考虑什么情况下大数太多不能拆下来,然后就 GG 了,因为这个讨论是递归的,无穷无尽的。
然后就想到了从 \(0\) 开始递推,往后推,记录能组成多少个活动的 \(i\),和不活动的 \(i\) 配对。看起来很对,甚至写了一发。
但是寄了,原因在于一个现在没用的数可以变成 \(0\),没法从头再推过一遍。
在这里就放弃了,去看题解。正确的做法是从后往前推,记录当前还需要至少 \(need\) 个 \(i\),而对于数可以变成 \(0\) 的问题,现在没用的数可以直接让 \(cnt_0\leftarrow cnt_0+1\),因为 \(0\) 是最后扫的,所以没有冲突。
然后就差不多了,剩下的问题是维护这个东西。\(O(n\sqrt n)\) 的话就是发现让 \(need\) 增加至多根号次(否则就爆 \(n\) 了),在线段树上 dfs,可以证明不带 \(\log\);zak 的 \(O(n\log^2 n)\) 的话维护分段函数,发现每一段的斜率不降且都是 \(2^k\),而值域 \(>n\) 的部分可以截掉,所以只有 \(\log\) 段,暴力维护即可。有个细节是可能有的段只有 1 个数,所以斜率可能会爆 long long,但是不影响复杂度分析(拐点不在整数处),此时直接把斜率重设为 1 即可。
其实我现在比较想知道的是我应该怎么想到是从后往前推而不是从前往后。
可能是应该都尝试思考一遍,另外“伸手要钱”的递推方式会比“主动馈赠”的递推方式要好一点吧。
然后递推的方向应该和特殊转移的方向相同,这样可以避免根基被挖了然后再推一遍。
简要题意:有两个钻石和 \(n\) 个摄像头,每个摄像头监视着第一个和/或第二个钻石,且有个破旧度 \(s_i\)。你每次可以叉一个摄像头,使其在接下来 \(s_i\) 秒内失效,当监视一个钻石的所有摄像头都被叉掉了的时候你可以花一秒偷走它。你必需先偷第一颗钻石再偷第二颗。求两颗都偷走的最小时间。\(n\le 1500,s_t\le 2n\)。
关卡目标:时间复杂度 \(O(n^2)\)。
点击查看题解
不会做一点。贪心和二分全都假光了。
以后看到这种题尽量往霍尔定理上去想而不是各种奇怪的贪心。各种贪心都有其不对劲的地方。何况这题其实很霍尔了:每个时间点可以干一件事 \(\Leftrightarrow\) 每件事要匹配一个时间点,这样能干完所有事 \(\Leftrightarrow\) 存在事到时间的完美匹配,就可以霍尔定理了。
在霍尔定理的基础上进行一个类似于反悔贪心的过程可以做到 \(O(n^2)\),不带 \(\log\)。
简要题意:给定一个有向图 \(G\),你需要构造一个点集,满足点集内的点两两之间没有边,且所有点集外的点可以由点集内的点走不超过两条边到达。\(n,m\le 10^6\)。
点击查看题解
解锁新技能:分步构造
被 *3000 彻底创死而毫无还手之力。
首先考虑 DAG 怎么做:每次剥掉入度为 0 的点,然后把它指向的点全部删掉,显然满足条件。
但是,这不仅满足条件,还满足加强了的条件:点集外的点可以由点集内的点走不超过一步到达。
于是我们考虑利用这一空闲进一步搞点事情。
具体地,我们首先跑一个贪心,找一个点集,使得原图每个点能由这个点集走不超过一步到达,但是不满足两两之间没有边。
这个贪心是简单的:每次拎出一个点,把出点全部删掉。
然后发现选出的这些点形成了一个 DAG!
于是再做一遍 DAG 上的贪心,一步 + 一步 = 两步,做完了。
妙哉。
总体思路就是先构造一个不满足一些条件但是加强满足其他条件的解作为中转,然后再对这个解牺牲加强的那部分来满足剩下的条件。
简要题意:给定一个长为 \(n\) 的序列 \(a\),定义区间 \([l,r]\) 的权值 \(a_{l,r}\) 为最大的只在这个区间中出现过的数(不存在定义为 \(0\))。请找出一个序列 \(b\) 使得对于所有区间 \([l,r]\) 有 \(b_{l,r}=a_{l,r}\),并最大化 \(\sum b_i\)。\(n\le 5\times 10^5\)。
点击查看题解
到后面差一点没有想完。
首先重新表述题目为有若干个带权的有效区间,一个区间的权值是其包含的权值最大的有效区间,剩下的位置是无效的。
那么首先有效区间的端点肯定是不变的,然后我们要给剩下那些无效的位置赋值。
有各种各样的直接贪心的想法,但是会被这个东西叉掉:
1 1 1 1 4 3 3 3 3
最优解是 1 2 2 1 4 3 2 3 3
,最后只改变了一个 3
而留下了另一个,就显得很奇怪。
于是只好抛弃感性,慢慢分析。
首先所有非关键的数字都相同,否则把较小的那个变成较大的那个一定依然合法。
于是我们枚举这个非关键的数字。但是然后呢?要怎样才能使它合法呢?把非关键的位置都填了可能变劣,不都填可能不合法。
然后就卡住了。
正确的思路:找到使它合法的那个对象,改为枚举那个对象。
什么对象能使它合法?当它包含一个比它大的关键区间的时候就合法。于是我们改为枚举那个关键区间。
剩下的就好办了:设这个关键区间为 \([L,R]\),值为 \(x\),那么这个非关键的数字一定是小于 \(x\) 的最大的未出现的数字 \(y\),所有 \(\ge x\) 的非关键位置填成它们可行的最优值,其它位置都填成 \(y\),如果还不合法,找到 \(L\) 左边最小的非关键位置和 \(R\) 右边最小的非关键位置变成 \(y\) 即可,现在最优性就很显然了。
复杂度 \(O(n\log n)\)。
关键点:我们不知道怎么让一个对象合法最优,于是我们改为枚举使得这个对象合法的条件,找到在该条件的前提下最优的对象。
简要题意:有 \(n\) 张卡,第 \(i\) 张卡直接买需要 \(a_i\) 块钱,还可以选择花 \(X\) 块钱随机抽卡,抽到相同的则会返还 \(X/2\) 块钱,求把所有卡都买下来需要的最小期望钱数。\(n\le 100,\sum a_i\le 10000\)。
点击查看题解
又是被 *3000 创死的一天。
首先把返还 \(X/2\) 块钱弄成如果还剩 \(i\) 张卡则花 \((n/i+1)X/2\) 抽一张是很自然的。
然后买了之后还去抽显然是很蠢的,严谨证明也不难。
但是然后就卡住了:对于一种情况,是直接买完还是开抽?
可能这个时候应该大胆进行一个猜测,就是这一选择只和剩下的 \(\sum a_i\) 有关,否则不太可做。
至于合理的思路,应当尝试把其中一种策略给“等价”成另一种策略,这样才能在同一个层次上比较。
事实上,“直接买完”可以视为“花 \(\sum a_i/k\) 的代价在剩下的 \(k\) 张卡中随机抽一张”。显然是对的。
于是比较 \(\sum a_i/k\) 和 \((n/i+1)X/2\) 即可判断。
背包即可。复杂度 \(O(n^2\sum a_i)\)。
关键在于把其中一种策略给“等价”成另一种策略。
简要题意:现在有 \(n+m\) 张牌,其中 \(n\) 张写着 \(1\sim n\),剩下 \(m\) 张是鬼。一个人玩游戏,每次把牌洗乱,依次拿牌并记录下上面的数字直至遇到鬼牌,然后再次洗乱并继续。当所有数字都被记录过且当前拿到了鬼牌的时候停时。求期望拿牌张数。\(n\le 2\times 10^6\)。
关卡目标:不要使用组合数。
点击查看题解
算期望的好题。
一开始想的是 min-max 容斥,但是发现这意味着“当前拿到鬼牌时停止”这个条件就显得特别鬼畜。用组合数继续推肯定能推出来,不过应该没什么意义。
考虑这样定义停止条件的好处:每一轮(直到拿到鬼牌算一轮)拿的张数是互相独立的,拿牌总张数为 期望轮数 * 一轮拿的期望张数。
一轮拿的期望张数可以拆掉,每张数字牌合法当且仅当在所有鬼牌前面出现,独立概率 \(1/(m+1)\),总期望张数 \(n/(m+1)+1\)(记得算上一张鬼)。
轮数显得奇怪一点,考虑扔掉无关变量以简化问题。
什么是无关变量?我们数轮数,可以视为数拿到的鬼牌数。而如果一张牌曾经拿过,那么它对我什么时候拿到鬼牌没有影响,对拿到其他牌的顺序也没有影响。它就是无关变量,扔掉。
所以可以视为一张拿过的牌就是直接扔掉的。
发现同一轮内拿到的牌也可以视为直接扔掉。
所以可以视为不断随机拿牌,每次拿一张,是鬼牌继续,是新牌扔掉,求期望拿过几次鬼牌。
显然还剩 \(k\) 张牌的时候会拿 \(m/k\) 次鬼牌。注意此时没有算最后一轮的鬼牌,加上,就是总共 \(mH_n+1\) 轮。
答案即为 \((mH_n+1)(n/(m+1)+1)\)。
关键思路:面对一些比较麻烦的限制,要想办法找到它简单的一面;记住将“第一个出现”改为“在第一个出现之后不算贡献”,方便拆开。
简要题意:有 \(n\) 个数 \(a_i\),每次你可以选择两个数 \(i,j\),把 \(a_i\) 加到 \(a_j\) 上,然后把 \(a_i\) 删掉。求至少经过几次操作把 \(a\) 变成单增的。\(n\le 15\)。
关卡目标:做到 \(O(3^nn)\)。
点击查看题解
考虑一个 dp \(f_{S,S_0,j}\) 表示当前已经用了 \(S\) 中的数,当前把 \(S_0\) 里面的数加起来放在了 \(j\) 这个位置上,需要的最少操作步数。
然后发现(我居然没发现!啊啊啊啊)dp 值值域很小,于是果断交换两维,设 \(f_{S,i,j}\) 表示当前已经用了 \(S\) 中的数,当前答案为 \(i\),放到了 \(j\) 上面,和最小是多少。
直接 dp 可以做到 \(O(3^nn^2)\)。可过,但是追求更优。
一个很关键的思路:找到 dp 转移中“没有用”的那一维。
然后我们发现转移过程中三个维度几乎都是“没有用”的,也即转移的值和 \(S\) 没有关系。
所以这时候我们考虑通过偏序的角度把其中一维省掉。
观察转移式:对于 \(S,i,j\),\(sum_T\longrightarrow f_{S\cup T,i+1,\min_{k>j,k\in T}k}\),条件为 \(f_{S,i,j}<sum_T\)。
发现其中最“简洁”的限制是 \(i\) 这一维(其实可以枚举每一维看哪一维最简洁),同时 \(i\) 具有偏序关系(越大越优),所以考虑把 \(i\) 这一维吃掉。
然后注意到条件很简洁,是一个简单的 \(<\) 号,所以考虑把它丢进一个偏序结构里面。
然后做法就能出来了:把所有 \(f_{S,i,j}\) 和 \(sum_T\) 拉出来排个序,扫到一个 \(f_{S,i,j}\) 的时候把它记录下来,它的有用点只在于对 \(k>j\) 的位置放上一个 \(i\);扫到一个 \(sum_T\) 的时候枚举 \(t\in T\) 取出 \(t\) 位置上放的值即可。
转移的复杂度是 \(O(3^nn)\) 的,排序的总长度是 \(O(3^n+2^nn^2)\) 的,所以带上个 \(\log\) 也是 \(O(3^nn)\) 的,总复杂度就是 \(O(3^nn)\) 的。
简要题意:有一个 \(n\) 个点的无向图,求有多少种方案给每个点放上一个字母,使得图中存在一个回文哈密顿路径。\(n\le 12\)。
关卡目标:会证明自己的复杂度。
点击查看题解
从来没见过这么玩的,存在性计数,但是直接使用 set 去重。
(其实成立的原因是所有图的回文哈密顿路径条数是合理的)
首先我们爆搜所有可能的首尾匹配,方案数 \(11!!=10395\)。
然后判一下这个匹配是否合法,可以 \(10395\times 6!=7484400\) 暴力判。
然后搜所有字母相同的位置集合,方案数是贝尔数 \(B_6=203\)。
于是总方案数为 \(10395\times 203=2110185\),把得到的字母集合往 set 里面扔。
最后在 set 里面数一数即可。
\(\color{blue}\dagger\) + ## CF1572E Polygon
简要题意:给定一个 \(n\) 个点的凸多边形,把它划 \(k\) 刀互不相交的刀切成 \(k+1\) 块,最大化最小那块的面积。\(n\le 200\)。
点击查看题解
糖丸了。
首先二分答案,然后写了半天的 dp 转移式,各种推,翻转答案维和 dp 维等等,但都失效,只能做到 \(O(n^5)\) 或 \(O(n^4\log W)\)。
事实上只需要 dp 值记一个二元组就好了:优先最大化分的块数,其次最大化剩下的面积。显然是对的,因为剩下的面积再多留着也不如再分一块。直接做即可。\(O(n^3\log W)\)。
真的怎么都没往“dp 值记一个二元组”上面想/ll,不过看起来以后记得这一点就好(?)
\(\color{black}\dagger\) + ## CF1951I Growing Trees
简要题意:给定 \(n\) 个点 \(m\) 条边的图,每条边有边权 \(a_i,b_i\),当一条边被选 \(x\) 次的时候,它会产生 \(a_ix^2+b_i\) 的代价。求在图中选出 \(K\) 棵生成树的最小代价。\(n,m\le 50,K\le 10^9\)。
点击查看题解
引理:每条边被选的次数数组 \(x_i\) 合法当且仅当对于任意一个子集 \(S\),\(S\) 的导出子图的边数 \(\le k(|S|-1)\)。
为什么呢?听说是 Matrix Partition,又称 Nash-Williams theorem。见这里。
要正常地想到这一点的话,应该就是考虑必要条件,然后考虑着考虑着看起来就像 Hall 定理,就得证了。
剩下的就是二分 delta 以及最大权闭合子图的事儿。