2024.3.9 - 3.15
Sat
LGR-176(Div.2)
A. 区间和问题,一眼盯真:前缀和。
B. bfs,顺便记一下转移方向。
C. 最小化最大值,二分答案,用点 DS 实时维护逆序对即可,笔者用了线段树。
D. 区间DP,预处理一下 \(a_i^{a_j}\) 的值,然后记 \(f_{l,r,0/1}\) 表示到达了 \([l,r]\) 区间,并且最后一步是取了头部/尾部到达该状态,从 \(f_{1,n-1,1}\) 与 \(f_{2,n,0}\) 开始即可。
E. 先离散化,然后二分,双 \(\log\) 搞定(虽然正解单 \(\log\))。
F. 首先改删边为加边,使用 \(\mathcal{O}(1)\) 求 LCA,并且用并查集合并,实时维护每个连通块当时的直径长度(multiset
等),两个端点,运用结论:合并两棵树的直径的端点一定是原两棵树的两条直径的四个端点中的两个。
G. 可以枚举(有点事没写,虽然也不太会)(为什么枚举复杂度对了啊?!)
Sun
作业题
【省选联考 2020 A 卷】
给定图 \(G\),记 \(T\) 是 \(G\) 的一棵生成树,\(e\) 是 \(G\) 中的一条边,\(w(e)\) 表示 \(e\) 的边权,求:
其中 \(|V|\leq 30, w(e)\leq 1.6\times 10^5\)。
欧拉反演,得到:
然后拉出权值是 \(d\) 的倍数的边,求所有生成树的边权和,这并不好用矩阵树定理处理,但是考虑多项式 \((w(e)x+1)\),这可以使得乘法转加法,在 \(\pmod {x^2}\) 意义下进行多项式加减乘法和多项式求逆。
当然,考虑对于常数项为 \(0\) 的多项式,此时没有逆,直接用一次项进行消元。
附:多项式求逆(牛顿迭代式):设已知 \(F\) 是 \(A\) 在 \(\pmod {x^{\lceil{\frac{n}{2}}\rceil}}\) 意义下的逆,要求 \(G\) 是 \(A\) 在 \(\pmod {x^n}\) 意义下的逆,有:\(G(x)=2F(x)-F^2(x)A(x)\),在本题中次数较低,可以直接一次迭代搞定。
Mon
天赋
给定一棵以 \(1\) 为根的树,求外向生成树个数。
\(1\leq n\leq 300\)。
矩阵树定理模板题,不做多说。
OI游戏
给定一个 \(n\) 个点的图 \(G\),求满足如下条件的 \(G\) 的生成树 \(T\) 个数:
- 对于所有节点 \(i\in [2,n]\),有 \(G\) 中 \(1\) 到 \(i\) 的最短路等于 \(T\) 中 \(1\) 到 \(i\) 的路径长度。
\(1\leq n\leq 50, 1\leq w(e)\leq 9\)。
首先用 Dijkstra 跑出每一个节点可以从哪些节点更新最短路径,然后以此建树,跑以 \(1\) 为根的外向生成树个数。
文艺计算姬
求完全二分图 \(K_{n,m}\) 的生成树个数。
\(1\leq n,m\leq 10^{18}\)。
矩阵树定理打表,注意到答案等于 \(n^{m-1}m^{n-1}\)。
证明:不妨考虑 Prüfer 序列,序列中的最后两个点之间一定有边相连,故这两个点一定满足一个在左部点集,一个在右部点集。每次删除一个点集中的一个点,都会加入另一个点集中的一个点,可以得出答案为 \(n^{m-1}m^{n-1}\)。
applese数图
求无自环、无重边的 \(n\) 个点的生成树数量小于等于 \(k\) 的带标号无向连通图的数量。
\(1\leq n\leq 10^6, 1\leq k\leq 22\)。
引理 1:图 \(G\) 的生成树数量等于 \(G\) 中各点双连通分量的生成树数量之积。
感性理解: \(G\) 中各点双连通分量选一棵生成树拼起来就是 \(G\) 的一棵生成树。
最简单的点双为 \(C_n\),其生成树数量为 \(\dfrac{(n-1)!}{2}\),圆排列计算即可,此时 \(|V|=|E|\),且不存在其它样子的图。
若 \(|E| > |V|\),不妨考虑 \(|E| = |V| + 1\),此时为 \(C_n \cup (u,v)\),三度点为 \((u,v)\),三条路径的长度分别为 \(x,y,z\),有 \(x+y+z=n+1\),则生成树个数为 \(xy+xz+yz\),其最小值为 \(3n-4\),故当 \(|E| > |V|\) 时生成树个数不小于 \(3n-4\),此时 \(n\leq 8\)。
且对于一个大小 \(\ge 3\) 的点双而言,其生成树 \(\ge 3\),故这样的点双最多两个。
若点双为 \(0\) 个,此时为树,共计 \(n^{n-2}\) 个。
若点双为 \(1\) 个,不妨记 \(f_{V,K}\) 表示 \(V\) 个点的点双连通图有 \(K\) 棵生成树的方案数,这个需要预先打表处理 \(n\leq 8\) 的所有情况。我们需要在 \(n\) 个点中选 \(V\) 个点组成该点双,方案数有 \({n\choose V}\) 个,并与剩余点组成树。
引理 2:设 \(n\) 个点组成一个 \(k\) 个连通块的森林,各连通块大小为 \(a_1,a_2,\cdots,a_k\),那么总共有 \(n^{k-2} \overset{k}{\underset{i=1}{\prod}} a_i\) 棵树包含该森林。
故此时方案数为 \(n^{(n-V)+1-2}\times V\times f_{V,K}\times {n\choose V} = n^{n-V-1}\times V\times f_{V,K}\times {n\choose V}\)。
若点双有 \(2\) 个,枚举两个点双的大小 \(V_1,V_2\) 与生成树个数 \(K_1,K_2\),其内部有 \(f_{V_1,K_1}\times f_{V_2,K_2}\) 种决定形态。
-
若两个点双属于不同的边双,即此时两个点双不交,那么有共计 \({n\choose V_1}\times {n-V_1 \choose V_2}\) 种方案布点,根据引理,有 \(n^{(n-V_1-V_2)+2-2}\times V_1\times V_2\) 种方案将它连进图中,故该种情况方案总数为 \(({n\choose V_1}\times {n-V_1 \choose V_2})\times (n^{n-V_1-V_2}\times V_1\times V_2)\times (f_{V_1,K_1}\times f_{V_2,K_2})\)。
-
若两个点双共同组成一个边双,即此时两个点双交于一点,那么有共计 \(n\times {n-1\choose V_1-1}\times {n-V_1 \choose V_2}\) 种方案布点,根据引理,有 \(n^{(n-(V_1+V_2-1))+1-2}\times (V_1+V_2-1)\) 种方案将它连进图中,故该种情况方案总数为 \((n\times {n-1\choose V_1-1}\times {n-V_1 \choose V_2})\times (n^{n-V_1-V_2}\times (V_1+V_2-1))\times (f_{V_1,K_1}\times f_{V_2,K_2})\)。
用 \(\mathcal{O}(k^4)\) 复杂度枚举可以通过,打表程序需要约 \(8\sim 15 \min\) 时间运行。
简单的数学题
给定正整数 \(n\),质数 \(p\),求如下表达式的值对 \(p\) 取余的结果:
\(1\leq n\leq 10^{10}, 5\times 10^8\leq p\leq 1.1*10^9\)。
算法 \(1\):莫比乌斯反演
令函数 \(f(x)=x^2\varphi(x), g(x)=x^2\),则 \((f\cdot g)(x) = \underset{d\mid x}{\sum} d^2\varphi(d) \frac{x^2}{d^2} = x^3\),可以杜教筛。
算法 \(2\):欧拉反演
殊途同归,令函数 \(f(x)=x^2\varphi(x), g(x)=x^2\),则 \((f\cdot g)(x) = \underset{d\mid x}{\sum} d^2\varphi(d) \frac{x^2}{d^2} = x^3\),可以杜教筛。
时间复杂度为 \(\mathcal{O}(n^{2/3})\)。
附:令函数 \(f(x)=\mu(x), g(x)=x\),则 \((f\cdot g)(x) = \underset{d\mid x}{\sum} \mu(d) \frac{d}{x} = \varphi(x)\)。
Tue
生成树计数
【NOI2007】
给定一条 \(n\) 个节点的链,然后将距离在 \([2,k]\) 范围内的点对相连得到 \(G\),求 \(G\) 的生成树数量。
\(2\leq n\leq 10^{15}, 2\leq k\leq \min(5,n)\)。
首先,考虑 \(n\) 比较大的情况,我们列出 \(n=9,k=3\) 的基尔霍夫矩阵,且以下讨论 \(k=3\),其余可以拓展:
运用一下行列式的小技巧,我们可以将其在乘上几个 \(-1\) 后变成:
看得出规律吗?或者再观察 \(n=15\) 时的样子:
前 \(n-2k-1\) 行有一个上三角!不妨在计算行列式时抛弃最后一行与最后一列,这样前 \(n-2k-1\) 行就可以覆盖 \(n\) 列中任何一个长度为 \(2k+1\) 的连续区间。
接下来,第 \((n-2k)\sim (n-k-1)\) 行的数字在左边,看起来很不爽,我们把它消到右边去,考察其中的第一行 \([3,-1,-1,-1,0,0,0]\),如何消元?
很好,我们总是可以通过选择上面中的某一行,乘上最左边的非零值,加到该行,使得最左边的非零值变为 \(0\),且非零值数量保持在 \(2k\) 以内,直接令其为 \([a_1,a_2,a_3,a_4,a_5,a_6,0]\)。
线性递推!也就是说,\([a_1,a_2,a_3,a_4,a_5,a_6]\) 的转移矩阵为:
矩阵快速幂递推,此时左部消元到了右边,接下来,右下角还有一小部分,暴力消元即可。
不要忘记上面的一些 \(-1\),以及换行的 \(-1\)。
同时 \(n\) 较小的时候(\(n\leq 2k\))这个矩阵没有什么好的性质,暴力消元即可。
FWT初探
Nim Game
Nim 游戏,FWT 优化 DP 递推。
考察:给定 \(n\) 个非负整数 \(w_i\),描述一个数集,且需要构造一个 \(m\) 堆石子的 Nim 游戏,每堆石子的数量必须属于该数集,求构造先手必胜局面的方案数。
\(w_i\leq 10^5, m\leq 10^9\)。
递推很显然,记 \(f_{i,j}\) 表示考虑了 \(i\) 堆且当前 \(\text{SG}=j\) 的方案数,则根据 SG 定理:
用 FWT 优化即可,点值意义下快速幂。
按位或
【HAOI2015】
初始一个变量为 \(v=0\),每次在 \([0,2^n)\) 范围内按照概率选定一个非负整数 \(x\),并将 \(v\) 按位或上 \(x\),求使得 \(v= 2^n-1\) 的期望时间。
\(1\leq n\leq 20\)。
先拆成 \(n\) 位二进制,设 \(S\) 表示赋成 \(1\) 的二进制位,\(\max(S),\min(S)\) 分别表示将 \(S\) 中的位赋成 \(1\) 的时间中的最大值与最小值,则 \(E(\max(U))\) 为所求。
\(\min-\max\) 容斥,可得 \(E(\max(U)) = \underset{T\subseteq U}{\sum} (-1)^{|T|+1} E(\min(T))\),考虑求 \(E(\min(T))\)。
显然,就是至少有一位与 \(T\) 有交的数字的概率之和的倒数,那么问题转变成与某些数位有交的下标的权值的和。
不妨改成计算无交,即为 \(U \setminus T\) 的子集,FWT 即可。
于是复杂度可以在 \(\mathcal{O}(2^nn)\) 的复杂度内求解。
子集卷积
给定两个序列 \(A,B\),求如下卷积式:
长度在 \([1,2^{20}]\) 之间,且是 \(2\) 的幂。
化条件:\(i\mid j = k\) 的条件是容易的,直接按位或卷积即可,而 \(i\And j=0\),不好处理,不妨令 \(\operatorname{popcnt}(x)\) 表示 \(x\) 二进制下 \(1\) 的个数,则该条件可以化为 \(\operatorname{popcnt}(k) = \operatorname{popcnt}(i) + \operatorname{popcnt}(j)\)。
此时,令 \(f_{i,S}\) 表示集合 \(S\) 所有大小为 \(i\) 的子集的序列元素之和,可以再记 \(g,h\) 描述答案与其它数列。
于是复杂度是 \(\mathcal{O}(n^22^n)\) 的。
Wed
魔法小程序
【清华集训2016】
跑以下程序:
define A[],B[],C[]
//Let n be the length of A, m be the length of B
define Magic(x,y,z)
{
if(z==n)
return x>=y;
if(x%A[z]<y%A[z])
return false;
return Magic(floor(x/A[z]),floor(y/A[z]),z+1);
}
define Main()
{
for i=0 to n-1 do:
for j=0 to i do:
if(Magic(i,j,0) == true)
C[i]+=B[j];
Output(C)
}
并给出在给定输出数据下的输入数据,\(n\leq 10^4, m\leq 10^6\)。
程序很像 FWT,只不过第 \(i\) 层的长度是 \(a_i\) 的前缀积,于是对着 \(C\) 逆着做该类 FWT 即可。
需要跳过 \(A_i=1\),否则复杂度不对。
Tree Cutting
【HDU5909】
给定一棵 \(n\) 个节点的树,每个点有 \([0,2^m)\) 内的点权,\(\forall k\in [0,2^m)\) 求异或值为 \(k\) 的连通块个数,答案对 \(10^9+7\) 取余。
\(T\leq 10,n\leq 10^3,m\leq 10\)。
记 \(f_{i,j}\) 表示考虑到以 \(i\) 为根的子树,异或值为 \(j\) 的连通块个数,每遍历一棵子树,则:
发现是异或卷积,用 FWT 优化即可,但是因为空树可以向上传递,每离开一棵子树,要先变回来让 \(f_{now,0}\) 加一再变回去。
时间复杂度为 \(\mathcal{O}(n2^mm)\)。
期望浅算
设变量 \(X\) 的分布满足 \(P(X=n) = (1-p)^{n-1}p\),求 \(E(X)\)。
即:每一时刻往前走的概率是 \(p\),不走的概率是 \((1-p)\),则向前走一步的期望时间是 \(\frac{1}{p}\)。
遗失的答案
【SNOI2017】
给定正整数集 \(S=\{x\mid 1\leq x\leq n\}\cap \mathbb{N}^+\),再给出 \(Q\) 个询问,每一次询问给出正整数 \(X\),求有多少个集合 \(T\subseteq S\) 满足:
- \(X\in T\)。
- \(T\) 中元素的最大公约数是 \(G\),最小公倍数是 \(L\)。
\(n,G,L,X\leq 10^8, Q\leq 10^5\)。
首先判掉 \(L\) 不是 \(G\) 的倍数的情况,此时显然答案为 \(0\)。
否则我们可以让 \(n,L\) 都整除 \(G\),表示之后选数的要求为最小公倍数为 \(L'\)(以下 \(L\) 全部指整除后的),最大公约数为 \(1\)。
不妨对 \(L\) 进行质因数分解,在该意义下,就是对于每一个 \(L\) 的质因子,都有一个数顶满最高指数,也有一个数不包含该质因子。
发现 \(L\) 以内的最大质因子数量为 \(\max\{\omega(L)\}=8\),我们不妨直接状压所有质因数的状态:是否有一个数该质因子的指数为 \(0\),是否有一个数该质因子的指数与 \(L\) 一致。
这需要一个 \(2^{2\max\{\omega(L)\}}\) 的状态,可以接受,而合法状态就是 \(2\max\{\omega(L)\}\) 位全为 \(1\)。
我们考虑其每一个约数的时候,其实只需要考虑这些指数的状态,所以我们将约数按此分组,对于状态为 \(\text{sta}\) 的数有 \(k\) 个,那么以此进行更新状态的方式有 \(2^k-1\) 种,全部不选无法更新不是吗?(后文称之为“类”)。
记 \(f_{0/1,i,j}\) 表示(从前到后/从后到前)考虑到了第 \(i\) 类,当前状态为 \(j\),则更新是简单的,分别考虑选/不选即可完成 DP。为什么要这么做呢?因为我们将钦定 \(X\)。
接下来需要完成前后缀合并,考虑到 \(f_{0,i}\),我们要让其与 \(f_{1,i+1}\) 进行 Or 卷积,这可以使用 FWT 进行计算。
最后对每一类进行答案的计算,就是当状态 \(j\) 与该类的状态 \(\text{sta}\) Or 得到的数满足条件 \(2\max\{\omega(L)\}\) 位全为 \(1\),那么就可以增加 \(f_{i,j}\times 2^{k-1}\) 种选数的状态,因为 \(X\) 已经强制选了。
判一下 \(X\) 的一些奇奇怪怪的情况,此时答案为 \(0\)。
Thur
完美的旅行
【2018集训队互测】
给定一张 \(n\) 个点的图,\(i\to j\) 有 \(E_{i,j}\) 条边,我们定义 Trip 为从一点出发走至少一条边到达另一个点,而一个 Trip 的愉悦值为起点与终点编号按位与的结果。
定义一个 Journey 为若干个 Trip,而一个 Journey 的权值是所有 Trip 愉悦值按位与的结果。
\(\forall x\in [1,m], y\in [0,n)\) 求有多少种走 \(m\) 条边且权值为 \(n\) 的 Journey。两个 Journey 不同仅当 Trip 次数不同或存在一个 Trip 不同。
保证 \(n\) 是 \(2\) 的幂,\(n\leq 64, m\leq 2\times 10^4\)。
首先考虑枚举一个 \(S\),接下来要求所有点必须包含 \(S\) 为子集(即点编号是 \(S\) 的超集,后文称之为“编号条件”),这方便我们的计算,且可以通过 and卷积逆变换 求答案。
设计 \(f_{i,j}\) 表示走了 \(i\) 步,当前位于点 \(j\) 的方案数,则:
- 延续该次 Trip,则 \(f_{i,j}\times A_{j,k}\to f_{i+1,k}\)。
- 新开一个 Trip,因为每一个 Trip 都要求至少走一步,不妨枚举走一步后到达的位置,则 \(f_{i,j}\times c_k\to f_{i+1,k}\),其中 \(c_k\) 表示所有满足“编号条件”的点到达 \(k\) 号点的边的总数量。
初始化也需要走一步,最后的答案就是所有满足“编号条件”的点的 \(f_{m,i}\) 总和。
这看起来可以矩阵快速幂优化,不妨令 \(P\) 表示初始状态,\(Q\) 表示所有满足条件的点,\(F\) 表示转移矩阵,则对于 \(S\) 而言 \(g_{i,S} = PF^{i-1}Q\),其中有一步是第一个 Trip。
直接递推 \(F\),复杂度是 \(\mathcal{O}(n^3m)\),但是依据“光速幂”思想,按照 \(B\) 分块,本题取 \(B=\sqrt{m}\),处理出 \(\forall i\in [0,B]\) 的 \(PF^i\) 与 \(F^{iB}Q\),矩阵乘向量单次复杂度是 \(\mathcal{O}(n^2)\) 的。
于是总复杂度为:处理转移矩阵 \(\mathcal{O}(n^3)\),向量递推为 \(\mathcal{O}(n^3\sqrt{m})\),每一步的矩阵快速幂是 \(\mathcal{O}(n^4\log_2 \sqrt{m})\),以及计算答案的 \(\mathcal{O}(mn\log_2 n)\)。
心得:《论 FWT 的有效用法》
看到高维前缀和,高维差分后:
- 高维前缀和,子集求和,Or卷积变换。
- 高维前缀和,超集求和,And卷积变换。
- 高维差分,子集差分,Or卷积逆变换。
- 高维差分,超集差分,And卷积逆变换。
妈妈再也不用担心不会写高维前缀和与高维差分啦!
动态DP初探
The Best Teams
【Balkan2012】
给定 \(n\) 个二元组 \((u,v)\),按照 \(v\) 排序后相邻两项不能同时选,给定 \(q\) 个询问,每一个询问给出 \(u_{\max},k\),表示从 \(u\leq u_{\max}\) 中的所欲二元组按照规则选出 \(k\) 个,最大化选中二元组的 \(v\) 的和。
\(n,q\leq 3\times 10^5, 1\leq u,v,u_{\max}\leq 10^9\),且 \(v\) 两两不同。
动态不 DP,显然有结论:从大到小排序后能拿就拿。
考虑离线所有询问,按照 \(u\) 排序,用线段树维护最大的 \(v\) 的和,如何合并信息?由于 \([l,r]\) 的信息与 \(r+1\) 相关,令 \(now,ls,rs\) 分别表示当前节点与左右儿子,而 \([l,r],[l,mid],[mid+1,r]\) 表示节点的对应区间,不妨考虑:
- \(c_{now,0/1}\),表示若 \(r+1\) 选/不选,那么 \(l\) 选/不选。
- \(num_{now,0/1}\),表示若 \(r+1\) 选/不选,那么 \([l,r]\) 选多少个。
- \(sum_{now,0/1}\),表示若 \(r+1\) 选/不选,那么 \([l,r]\) 的最大和。
更新方法:
- 若 \(r+1\) 的状态为 \(0/1\),则 \(mid+1\) 的状态为 \(c_{rs,0/1}\),则 \(l\) 的状态为 \(c_{ls,c_{rs,0/1}}\)。
- 若 \(r+1\) 的状态为 \(0/1\),则 \([mid+1,r]\) 中有 \(num_{rs,0/1}\) 个选中,且已知 \(mid+1\) 的状态为 \(c_{rs,0/1}\),则 \([l,mid]\) 选中数量为 \(num_{ls,c_{rs,0/1}}\),最后 \([l,r]\) 的数量就是二者之和,\(sum\) 同理。
回答询问时在线段树上二分即可,时间复杂度为 \(\mathcal{O}((n+q)\log_2 n)\)。
最大权独立集
【树上动态DP模板】
给定一棵 \(n\) 个节点的树,点有点权 \(w_i\),接下来有 \(m\) 个修改操作,每一次修改改变一个点的点权,在每一次修改后计算该树的最大权独立集的权值和。
\(n,m\leq 10^5\)。
首先,这个问题的 DP 式子为:
考虑将所有轻儿子的答案记为 \(g_{i,0/1}\),表示 \(i\) 的所有轻儿子是否强制要求不选,则:
不妨再将 \(a_i\) 加到 \(g_{i,1}\) 上,考虑 \((\max,+)\) 矩阵乘法,可以写出:
但我们先访问链头,而初始信息在链尾,所以应当将转移矩阵写在前面,变成:
为了减少一些常数,可以记录每个点的转移矩阵。
Fri
保卫王国
【NOIP2018提高】
给定 \(n\) 个点,点有代价,你需要选择若干点,选点的代价为各选中点的代价和,在满足每条边都有至少一个端点被选中的情况下最小化代价。
\(m\) 次询问,每一次询问都选定两个点及选中情况,在满足这两个点的选点状态下做该问题。
\(n,m\leq 10^5\)。
首先这是一个最小点覆盖问题,运用相关结论得到:最小点覆盖=总代价-最大独立集(最大独立集的补集是最小点覆盖)。
于是该问题变成了模板题。完结!
然而并没有,我们如何解决必须选中/必须不选呢?
- 强制不选:也就是说强制在最大独立集中选中它,不妨将其的点权设为一个极大值,记为 \(I\),于是最终的最大独立集的权值要减去 \(I - a_u\)。
- 强制选中:也就是强制在最大独立集中不选它,不妨将其的点权设为一个极小值,且不会对最大独立集的权值产生影响。
每一次询问要做 \(4\) 遍修改,最终复杂度为 \(\mathcal{O}(m\log_2^2n)\)。