图论做题记录-1
CF1264F. Beautiful Fibonacci Problem
首先声明一个关于斐波那契数列的性质:\(F_{n+m}=F_nF_{m-1}+F_{n+1}F_{m}\)。
如果我们令 \(N=1.2\times 10^k\),我们注意到 \(F_{iN}\equiv0\pmod {10^k}\),于是我们有
从而我们得到 \(F_{iN+1}\equiv F_{N+1}^i\pmod{10^{2k}}\)。另外我们注意到 \(F_{N+1}=8t\times10^k+1,\gcd(t,10)=1\),于是我们有 \(F_{iN+1}=F_{N+1}^i=(8t\times 10^k+1)^i\equiv8t\times 10^ki+1\pmod{10^{2k}}\)。
因为题目要求对 \(10^{18}\) 取模,所以取 \(k=9\)。考虑令 \(A=125at^{-1}\bmod 10^9,D=125dt^{-1}\bmod 10^9\),并构造 \(b=AN+1,e=DN\),于是
这样子,我们一定能够找到一个子串等于 \(a+id\),从而构造正确。通过严谨的计算可以得到 \(125t^{-1}=368131125\),代入后输出即可。
CF1239E. Turtle
不难考虑到如果我们已经确定上面的数集,那么最优方案的已知的:上方单调递增,下方单调递减,利用调整法可以简单证明。现在考虑最大路径,假设从第 \(i\) 位开始拐弯的路径和为 \(S_i\),则 \(S_{i+1}=S_i+a_{i+1}-b_i\),因为 \(a_{i+1}\) 单增,\(b_i\) 单减,所以看出 \(S_{i+1}-S_{i}\) 单调递增,于是 \(S\) 的最大取值一定出现在 \(1\) 或 \(n\)。所以我们的最大路径和为 \(\max(\sum a+b_n,\sum b+a_1)\)。
与此同时我们应该可以简单看出 \(a_1,b_n\) 的值应当为最小的两个数,利用调整法证明即可,那么我们只需要让剩下的 \(2n-2\) 个数分成两个长为 \(n-1\) 的序列,并且 \(\max(\sum a,\sum b)\) 最小即可。考虑到 \(\sum a+\sum b\) 是一定的,假设为 \(s\),只需要让一边在 \(\ge \lfloor\frac{s+1}{2}\rfloor\) 前提下最小即可,不难看出可以利用背包 dp 简单实现,并且印因为我们只考虑可行性,可以用 bitset
优化,但需要注意此时不能滚动数组,否则难以进行构造。复杂度是 \(O(\frac{n^2\sum a}{w})\) 的。
CF521E. Cycling City
考虑直接在 dfs 树上找答案,则不难得出结论:当且仅当点 \(u\) 及其不同的子树拥有超过两条返祖边时,问题有解。假设两条返祖边分别为 \(v_1\to f_1,v_2\to f_2,\text{dep}_u>\text{dep}_{f_1}\ge\text{dep}_{f_2}\),则不难给出构造:\(u\to f_1,u\to v_1\to f_1,u\to v_2\to f_2\to f_1\)。
CF1142E. Pink Floyd
考虑没有粉边时其实是容易的:考虑维护一个集合 \(S\) 表示目前所有不可达的点,那么每次选择两个点询问,将指向的那个点删去,最后只剩下一个点即为答案。
接着考虑有粉边的状况,很明显我们不想让有粉色连边的点同时出现在集合 \(S\) 中,那么我们可以利用拓扑序,将当前粉边中入度为 \(0\) 的点加入集合,然后正常求解,将不合法的点删去,然而注意到此时并不代表 DAG 中剩下的点就不可行了,所以我们要将删点后新的入度为 \(0\) 的点加入集合,直到只剩下一个点,此时删去的所有点是可以通过绿边到达的,没有加入过集合的点是可以通过粉边可达的,所以构造合法。
考虑到粉边不一定形成一个 DAG,但只要我们的限制关系正确,保证集合 \(S\) 中不存在粉边的端点,就可以正确求解。于是我们用 dfs 将所有返祖的限制去除即可。
CF611H. New Year and Forgotten Tree
考虑按照 ? 的个数划分,那么我们可以统计出来两个大小之间的连边数量。容易想到如果对于任意非空大小集合,其都不存在环,也就是点数大于边数,那么一定存在解,这样我们可以 \(O(k2^k)\) 验证(\(k\) 是 \(n\) 的位数)。接下来考虑如何给出方案,不难考虑割掉叶子节点,我们考虑枚举叶子节点的边是处于哪两个大小之间,暴力改动后验证可行性即可,这样复杂度是 \(O(nk^32^k)\),可以通过。
CF1305G Kuroni and Antihype
对所有好朋友连边,并将题目中的操作改写,可以得到对 \(n\) 个点进行操作:
- 将一个点 \(u\) 染色。
- 寻找一个和点 \(u\) 相连的已经染色的点 \(v\),将 \(a_v\) 加入答案。
不妨考虑加入一个占位点 \(n+1\),且 \(a_{n+1}=0\),初始已经染色。这样考虑上述过程,应当生成了一颗树,不妨令边 \((u,v)\) 的权值为 \(a_u+a_v\),那么最后的答案即为 \(\sum w-\sum a\),因为 \(\sum a\) 是定值,则只需要让 \(\sum w\) 最大即可,也就是最大生成树。
考虑用 Kruskal 实现这个过程,因为朋友之间按为与为 \(0\),说明两者的和其实就是按位或。考虑从大到小枚举边权,则可以通过枚举子集得到可能的朋友的 \((a_u,a_v)\),暴力连尽可能多的边即可,复杂度为 \(O(3^k\alpha(n))\),其中 \(k=\log n\)。
ARC103F. Distance Sums
不难想到 \(d\) 最小的那个一定是重心,考虑从重心开始向下走,如果从 \(u\) 走到 \(v\),那么应当有 \(d_v=d_u+n-2\text{siz}_v\),因为到 \(v\) 的子树内的所有的距离少了 \(1\),其他点距离多了 \(1\),然而因为我们不知道 \(v\) 的 \(\text{siz}\) 所以会难以实现,只能利用搜索,复杂度难以承担。
不妨考虑倒序进行操作,即从叶子节点向上跳,这样当前处理的节点 \(u\) 的 \(d,\text{siz}\) 一定已知,相应的其父亲 \(f\) 的 \(d\) 也应当已知,因为有 \(d_f=d_u+2\text{siz}_u-n\),因为 \(d\) 互不相同,则如果 \(d\) 中有对应值存在,其一定唯一,那么我们可以找出所有节点的父亲,则树的形态已知。如果过程中找不到父亲,说明无解。
另外,我们需要检验重心处的 \(d\) 值是否准确,否则整个树的答案也将错误,用 \(\text{sum}\) 维护子树内的节点到根的距离和,简单传递后和重心 \(p\) 的 \(d\) 判断是否相等即可。
AGC025E. Walking on a Tree
考虑我们想让一条边正反都被走肯定最优,因此我们考虑一个回路状物,因为沿着回路走肯定可以将涉及到的边正反都走一边,这启发我们将所有路径的起点和终点连边,然后找出一条欧拉回路,按回路上的方向定向。
然而问题在于我们连出的图度数不一定都是偶数,也就是说不一定有欧拉回路。此时我们考虑补边,更具体来说,我们在 \(T\) 上 dfs,如果某个叶子节点的度数为奇数,就将其和父亲的连边加入图中。这样补齐后,对于这一条边的定向可以看作无用,然而一条边只会被加入一次,也就是说最多被删除一次,所以贡献是满的。对建出的图跑欧拉回路即可。
对于答案的统计,不难看出可以使用树上差分,并且我们发现因为定向的优异性,肯定不会出现只有两条路径经过同一个边,并且定向相同的情况,因此没有必要分开统计,直接在 \(c\) 数组统计后,将 \(\min(c,2)\) 累加到答案中即可。
AGC033F. Adding Edges
考虑对 \(G\) 进行压缩,更具体的,不难看出如果 \(G\) 中存在 \((a,b)(a,c)\) 的边,且 \(T\) 中存在顺次出现 \(a,b,c\) 的路径,则删掉 \((a,c)\),加入 \((b,c)\) 得到的 \(G'\) 不变。不难发现,这样操作完,一条边 \((x,y)\) 在 \(G\) 中出现当且仅当 \(T\) 中存在一条路径 \(p_1,\cdots,p_k\) 满足:
- \(p_1=x,p_k=y\)
- \((p_i,p_{i+1})\in G\)
那么我们考虑暴力进行这个加边过程,更具体的,不妨假设加入 \((x,y)\),令 \(p_{x,y}\) 是以 \(x\) 为根时,和 \(x\) 相连的点中距离 \(y\) 最近的点。考虑以下几种情况:
- \(p_{x,y}=y\),说明这条边已经存在,跳过即可。
- \(p_{x,y}\ne y\land p_{x,y}\ne \varnothing\),说明之前此时 \(x,y\) 连通,根据上面的推论,我们加入 \((p_{x,y},y)\) 即可。
- \(p_{x,y}=\varnothing\),说明 \(x,y\) 不连通,连接这条边,然后搜索出所有连通的点更新 \(p\) 即可。
最后统计答案只需要进行搜索,找到所有节点为根时有多少个点存在路径可以到达即可。注意到每一次搜索要么将 \(p\) 变为有值的,要么缩短一条边,因此总复杂度是 \(O(n(n+m))\) 的。
CF1264E. Beautiful League/LG4249. [WC2007] 剪刀石头布
如果连接 \(A\to B\) 表示 \(A\) 赢了 \(B\),那么题目本质想要让三元环的个数最大,不难想到对于一个不合法的三元组,一定恰有一个点在其中的度数为 \(2\),因此可以随意得到三元环的个数应为 \(\frac{n(n-1)(n-2)}{6}-\sum{\text{deg}_i\choose 2}\),考虑如何限制这个东西。
不难联想到平方费用流,每一个队伍的胜场每次加一,都对多出 \(\text{deg}\) 的代价。看出来这个代价是单调递增的,那么我们对每一支队伍拆点之后在之间连接 \([0,n-2]\) 的费用的边。对于每一场比赛,向对应的两个队伍连接流量为 \(1\) 的边,并且源点向所有比赛连接流量为 \(1\) 的边,用于限制每场比赛只能有一个队伍获胜。队伍和汇点连接流量为 \(+\infty\) 的边。最后只需要跑一边最小费用最大流即可,复杂度是 \(O(\text{AC})\)。
CF1338E. JYPnation
不难考虑到竞赛图如此优良的性质,我们发现缩点后,如果两个点不在同一个 scc 中,那么他们对答案的贡献是 \(614n+1\),分为一个一步可达和一个不可达。
接着我们考虑一个 scc 中的点对的贡献,可以注意到点对的贡献最多只有 \(3\),因为如果存在长度为 \(4\) 的最短路,那么一定不满足题目中的特殊性质。因此我们只需要考虑距离为 \(1,2,3\) 的点对。距离为 \(1\) 的点对就是边的数量,考虑统计距离为 \(2\) 的点对,那么距离为 \(3\) 的点对可以简单容斥。如果 \((u,v)\) 的距离为 \(2\),那么 scc 中应当有 \(u\to a,a\to v,v\to u\) 这三条边,显然我们不能暴力,但我们可以发掘一些性质:假设存在边 \(u\to b,a\to b\),则一定存在 \(b\to v\),否则不满足特殊性质。关注 \(a,b\),我们发现他们都是 \(u\) 的出点,如果将 \(a\to b\) 看作 \(a\ge b\),那么我们只需要找到 \(u\) 的出点集合中的最大值统计一次即可。复杂度是 \(O(n^2)\)。
并且通过特殊性质,我们有一个优化:竞赛图缩点后的链上只有最后一个 scc 的大小可能 \(>1\)。
UOJ670.【UNR #5】获奖名单
考虑将回文串的两半部分放在一起,可以看出:因为每个人的名字最多只有两个字符,所以如果两个部分互相匹配,说明要么两者完全一致,要么是在两个一个字符的名字中有两个字符的名字交替出现。
后者可以考虑对字符连边,如此一来,整个过程应该可以写成 \(u\to a_1\to a_2\to\cdots\to a_k\to v\),这个东西不好维护,但我们可以对所以一个字符的名字连接 \(0\to u\) 的边,那么上面的路径会变成以 \(0\) 的起点的欧拉回路,于是我们正常跑欧拉回路并使相邻的边交替在两部分中出现。前者只需要利用 map
就可以简单进行匹配,匹配后一次放到答案两边即可。
还有一些特殊情况需要判断:如果长度为奇数,那么最后会有一条无法回到 \(0\) 的路径,需要注意;如果长度为偶数,那么可能有一个名字在对称中心处,这样的名字在统计相同名字时显然会多出来,将其放到正中间即可。
UOJ605.【UER #9】知识网络
首先我们考虑到一个点到同一个标签的知识点的最短路的长度差距不超过 \(1\),我们从这一点入手,对每一个标签进行求解:我们只需要求出有多少个点对的距离是最短路,利用容斥可以轻易求出有多少个点对的距离是最短路 \(+1\)。
我们先以一个标签的知识点为起点,跑出其在整个图上的最短路,可以利用 01bfs 做到 \(O(km)\)。接着有多少个点对的距离恰为最短路,等价于在最短路图上有多少个点可达该点,考虑利用 bitset
求解,那么我们可以做到 \(O(\frac{kn^2}{w})\)。注意到,对于一个标签,我们只需要该标签知识点数大小的 bitset
,于是我们可以手写 bitset
从而达到动态大小,则复杂度优化为 \(O(\frac{n^2}{w})\)。
然而此时的空间复杂度是 \(O(\frac{n^2}{w})\),无法通过这道题目。考虑利用 bitset
分块,将每 \(w\) 个点单独统计一次答案,那么空间复杂度下降至 \(O(n)\),时间复杂度不变。
UOJ32.【UR #2】跳蚤公路
考虑判负环的算法,在这里我们采用 Bellman-Ford。普通的 Bellman-Ford 算法令 \(f_{i,u}\) 表示从 \(1\) 出发不超过 \(i\) 步到达 \(u\) 的最短路,有负环当且仅当存在 \(u\) 使得 \(f_{n,u}<f_{n-1,u}\),这是对于确定的 \(x\) 求解,并且经过这个负环的点就是 \(u\) 所能到达的点。
考虑对于所有 \(x\),不难看出任意一条路径的权值可以写成 \(kx+b\) 的形式,并且不难看出 \(k=\sum s,b=\sum w\)。显然对所有相同的 \(k\),我们只会取 \(b\) 最小的一个。于是我们可以在原先 dp 的基础增加一维,令 \(f_{i,u,k}\) 表示从 \(1\) 出发不超过 \(i\) 步到达 \(u\) 且 \(\sum s=k\) 的 \(\sum w\) 的最小值,因为我们只关注简单环,所以 \(k\in[-n,n]\),因此普通 dp 的复杂度是 \(O(n^3m)\) 的。
求解出 \(f\) 后,有负环当且仅当 \(\min(ix+f_{n,u,i})<\min(jx+f_{n-1,u,j})\),我们需要求出这个解集,答案即为它的补集。考虑拆 \(\min\),那么可以看出解集是所有 \(i\) 保证 \(ix+f_{n,u,i}<\min(jx+f_{n-1,u,j})\) 的解集的并。继续拆 \(\min\),那么可以看出 \(ix+f_{n,u,i}<\min(jx+f_{n-1,u,j})\) 的解集是 \(ix+f_{n,u,i}<jx+f_{n-1,u,j}\) 的解集的交。那么求出答案解集是自然的,统计答案后输出即可。
UOJ552.【UNR #4】同构判定鸭
题目本质上想要让我们判断两个图形成的字符串多重集是否完全相同,不妨考虑哈希。令字符串的哈希值为其各个位置上的字符的哈希值的乘积,而一个字符串集的哈希值为其中字符串哈希值的和。这样我们容易将所有的字符串统一向后拓展一位,但要注意此时不同位置上的相同的字符对应的哈希值也不应相同,可以采用 mt19937
生成的随机数。
如果设 \(f_{u,k}\) 表示从 \(u\) 点开始的长度为 \(k\) 的字符串的哈希和,那么通过上面的定义,这个是容易 \(O(nm)\) 递推的。考虑怎么样找到一个不同的字符串,若令 \(g_u\) 表示以 \(u\) 为结尾且和当前字符串匹配的路径个数,那么两个图中不存在以当前字符串为前缀的出现次数不同的字符串当且仅当两个图的 \(\sum g_uf_{u,k}\) 不同,可以暴力判断这个东西,并且 \(g_u\) 也是容易递推的。
考虑什么时候应当判断两个图同构,应当考虑不合法的字符串的长度存在上界,且不难看出其上界为 \(n_1+n_2\),则我们可以在 \(O(nm|\sum|)\) 的复杂度内得出答案。
UOJ461. 新年的Dog划分
首先不难考虑到 \(\frac{n(n-1)}{2}\) 的做法:枚举每一条边,判断将其删除后图是否连通,连通则删除,否则保留,那么最后留下的一定是一个原图的生成树,那么我们可以直接对其跑黑白染色,从而得到二分图的一侧。至于如何判断其不是二分图,不难想到对于原图中的一个奇环,其在黑白染色后定然有相邻的黑点或白点,那么当删除两部分之间的非树边之后,其不会被删除,此时删除某条树边图依旧连通,因此可以用 \(n-1\) 次的代价判断,但显然前两个包并不需要。
考虑到枚举树边较劣,不妨考虑二分,对于一个前缀 \([1,mid]\),如果删除全部的彼岸图依然连通,说明其中没有要保留的边,否则需要二分找出最前的需要保留的边,也就是使得图不连通的边。这个过程会进行 \(n-1\) 次,每次都最多在 \(\frac{n(n-1)}{2}\) 条边中二分,则询问次数 \(<(n-1)\log\frac{n(n-1)}{2}<2n\log n\),加上判断是否合法的 \(n-1\) 次无法通过本题。
考虑对点进行二分,这样可以省去 \(2\) 的常数,也就是说我们对每个点二分其和哪些点的连边要保留。考虑到每个点最后均有一段区间没有保留的边,然而使用二分会多出一个 \(\log\) 次的询问,\(n\) 个点就会多 \(n\log n\) 次,所以这里需要较为精细的实现:每一次开始二分前先将所有边删除判断图是否连通,若连通则说明后面没有要保留的边,则不用进行二分。通过计算得出询问的上限是 \(n\log n+2n\le 2000\),因此可以通过。
LG8456.「SWTR-8」地地铁铁
考虑到存在一条路径两种边权都有这样的信息较难维护,可以转而考虑什么样的点对不存在这样的路径,不难讨论出以下两种情况:
- 两点之间只存在包含其中某一种边权的路径。
- 两点之间同时存在包含两条包含边权不同的路径,且两条路径互不干扰(即既不经过重复点,点集之间也没有边)。
对于第二种情况,这样的点对显然只可能出现在点双连通分量中,因此考虑对原图建立圆方树,然后可以考虑怎样求解。首先不难发现的是,一个点双中这样的点对最多只有一条,然后我们发现一个点双中存在这样的点对当且仅当只存在两个点在这个点双中存在两种边权的出边,证明是感性的。于是我们不难判断每一个点双是否存在这样的点对。
对于第一种情况,如果将内部的边的边权全部相同的点双称为纯色点双,那么这样的点对在圆方树上肯定只经过纯色点双,于是我们可以利用并查集将可以只通过纯色点双到达的点缩到一个连通块内,显然一个连通块内的点两两均符合条件。
对于以上讨论出的情况求解,用总点对数减去即可。总复杂度可以做到 \(O(n+m)\)。
LG9150. 邮箱题
考虑每次只会多得到一个钥匙,那么我们能新走到的点不超过 \(1\) 个,因此我们下一个走的点是确定的,也就是当前点的 \(k\),所以我们走的路径可以看作是一条链。考虑我们现在从 \(i\) 开始走到了 \(j\),走过的点的序列称作 \(a\),能走到 \(k_j\) 当且仅当对于最大的 \(p\) 使得存在边 \(a_p\to k_j\),\(j\) 可以到达 \(a_p\)。因为这样我们可以重新到达 \(a_p\) 然后走到 \(k_j\),而这说明 \(j\) 和 \(a_p\) 在同一个强连通分量内。可以枚举所有 \(j\) 的返祖边和 \(k_j\) 并用并查集维护强连通分量,然后枚举所有入点 \(u\),如果 \(u,j\) 在同一个强连通分量内则可行。所以我们用并查集维护强连通分量,然后可以做到 \(O(n^2)\)。
考虑到 \(k\) 是固定的,那么我们一定只是在一些环上按顺序走,于是我们可以单独处理每一个环。我们先将每个环复制一份,然后从每个点开始向后走,能走到的最远点肯定最优。考虑到后面的点不会走到前面,所以我们从后往前枚举。对于当前已知的前两条可达链 \(s_1\to t_1,s_2\to t_2\),能合并当且仅当 \(s_2\) 可以在 \(s_1\to t_1\) 的条件下到达,也就是上面所说的条件,这个我们是可以按照上面的方法维护的,问题在于如何合并强连通分量,因为直接枚举第第二条链上的返祖边会不断枚举不产生贡献的返祖边。可以考虑对每一条可达链维护所有终点编号不小于 \(i\) 的没有考虑过的返祖边,合并的时候只需要枚举第二条链的所有返祖边,统计贡献后将它们删除即可,那么复杂度降为 \(O(n)\)。
考虑到如果 \(i\) 在被加入后才产生了新的合并,说明 \(i,t_1\) 一定是在同一个强连通分量内的。这样我们维护的内容就可以变成每一条链上最大的还有未统计的返祖边的强连通分量,因为前面一定是一个强连通分量,所以我们不在意返祖边具体指向那个点,因为不管指向哪里,我们总可以合并这两条链。
CF1515G. Phoenix and Odometers
考虑一个点想要回到自己,并且图是有向的,这启发我们进行 Tarjan 缩点。由于路径需要回到自己,那么我们不能走出这个强连通分量,必然只能在强连通分量内移动。
对于一个强连通分量,其中定然存在着若干个环,假设其长度分别为 \(l_1,l_2,\cdots,l_k\),通过裴蜀定理那么从这个强连通分量的一个点出发,存在路径满足条件当且仅当 \(\gcd(l_1,l_2,\cdots,l_k,t)\mid s\)。问题仅在如何求出 \(l\)。我们考虑按照 dfs 树的方式求环,然而这样子是会遗漏环的:假如图中存在 \(u\to v,v\to w,u\to w\) 的边,我们可能只会求出包含 \(u\to v,v\to w\) 的环,而 \(u\to w\) 因为是前向边而被遗漏。此时我们可以有两种处理方法:
- 考虑到我们以不同的根节点进行 dfs 跑出的环是不一样的,因此我们对于每一个强连通分量随机几个点作为根,这样我们大概率可以找到所有环。即使找不到所有环,得到的最大公倍数也有大概率是正确的。
- 考虑这样的两个环的差值,不难发现是两者边权和之差,因此我们可以建立双向边,并将反边的边权取反,这样原来的某一个环一定可以由某些环相加得到,根据 \(\gcd(a,b)=\gcd(a-b,b)\),我们可以得到这样的做法没有问题。
认为求 \(\gcd\) 的复杂度是 \(O(\log V)\),总复杂度是 \(O(n+(m+q)\log V)\) 的。
CF1361E. James and the Chase
容易发现一个点是好点当且仅当以其为根的 dfs 树上不存在横叉边和前向边,那么我们可以在 \(O(n)\) 的复杂度内判断一个点是否是好点。这并不优秀,所以我们想要得到一个批量求出好点的算法。如果我们以一个好点为根,那么如果一个点的子树内有两条到自己祖先的返祖边,那么这个点肯定不会是好点。否则,因为图的强连通特性,这个点的子树内一定恰有一条返祖边,假设其到达 \(v\),那么当前点为好点当且仅当 \(v\) 是好点,证明是容易的,于是我们只需要找到一个好点,就可以找到所有的好点。
问题在于如何找到第一个好点,暴力枚举显然不行,不妨考虑随机化,我们随机选取 \(100\) 个点当作根,如果找到了好点那么问题就解决了,如果没有找到,那么我们可以认为好点的个数不足 \(20\%\),否则我们 \(100\) 次都随不到好点的概率是低于 \(0.8^{100}\) 的,可以看作没有。于是我们在 \(O(100n)\) 的时间复杂度内解决了问题。