2022.2

2022.2

只记录一些我喜欢的题 还有一些模拟赛时没想到的 key observation

剩下的题只是因为我不会

2.8

T1

有时候不合法的决策一定不优于答案,这时候可以扩大决策集合。

这题就令 \(0\leq j<i\)\(j\) 都转移到 \(i\) 就裸的斜率优化了。

T2

话说这个按编号二进制下每位是否为 \(1\) 分类是不是很常见的思路啊。

2.10

T1

给你 \(n\) 个数,其中有 \(k\) 个奇数,你可以花费 \(c_{i,j}\) 的代价把 \(a_i\)\(a_j\) 同时减 \(1\),问最小花费。

\(n\leq50,k\leq8\)

但怎么建图?

考虑只有偶数,对 \(i,j\) 的一次操作看成 \(i,j\) 之间的一条边,所有操作构成一个图,每个点的度数都是偶数,所以一定可以拆分成若干个环,我们给环上的边定向(顺时针还是逆时针无所谓),每个点的入度都等于出度,这样我们建费用流时就可以把每个点拆成入点和出点,源点向出点连流量 \(a_i/2\) 的边,入点向汇点连 \(a_i/2\) 的边,出点和入点之间连流量正无穷,费用 \(c_{i,j}\) 的边。

加上奇数的话,所有操作构成的图就不能全部拆成环,还会多出一些首位是奇数点的链,注意到 \(k\) 非常小,于是可以 \(\binom{k}{k/2}\) 枚举那些奇数点是入度比出度大 \(1\)(其余的就是出度比入度大 \(1\)),从源点连的或连向汇点的边流量就是 \(\lfloor{a_i/2}\rfloor\)\(\lfloor a_i/2\rfloor\),这样就做完了。

T3

真的是太喜欢这个题了

第一次看到点分树这种用法

题意大概是给你一棵树,点 \(i\) 向树上距离 \(i\) 不超过 \(r_i\) 的点连边,形成一个有向图,求缩点 DAG 中入度为零的点个数。

\(n\leq 3\times 10^5\)

暴力建图做 tarjan 就 \(\Omega(n^2)\) 了,寄,原因在于边数太多

如果有一种复杂度可以接受的 dfs 方式搜一遍所有点,那 dfs 序的逆序就是拓扑序(忽略一个强连通分量里的顺序),在按拓扑序搜一遍就得到零入度点的个数了。

点分树

我们记录下每个点的各级分治重心,和每个点作重心时他那层的所有点,并按到重心距离排序。

这部分空间复杂度是 \(O(n\log n)\),我们再对每层维护一个指针(类似当前弧优化),这样遍历每层的复杂度也保证了。

我们现在 dfs 到点 \(x\),然后我们以此考虑 \(x\) 的各级分治重心,从指针指的位置继续往下 dfs,指针指的点到 \(x\) 的距离超过 \(r_x\) 就 break 掉,继续考虑下一个分治重心。

然后我们就发现整个 dfs 的复杂度就是 \(O(n\log n)\),What a coincidance!

2.12

T1

区间DP,感觉不太难啊,为什么做不出来

T2

挺好一个题,可惜被一车人的 \(O(n^2)\) 暴力吊起来艹,我 \(O(n\sqrt{n}\log n)\) 却毫无悬念拿了 \(50\) pts /fn

一个 key observation 就是答案的边一定在最小生成树上。

然后就只需对每个点维护其在 MST 上的孩子,具体地,我们要维护:

  • 该点的孩子的颜色集合
  • 每种颜色对应的边权的集合
  • 这些颜色对应的边权的最小值的集合
  • 所有点的各颜色对应的边权的最小值的集合的最小值的集合(其实就是全局的答案)

修改依次修改每个集合即可,总复杂度 \(O(n\log n)\)

总结:是一道非常好的 STL set 练习题

T3

给你序列 \(v\),计数满足下列条件的长 \(n\) 的正整数序列 \(a\)

  1. \(a_i\leq v_i\)
  2. 序列中不存在 \(\texttt{border}\)

模数 \(998244353\)\(n\leq 10^6\)

题面简洁,感觉像经典题(?

先设计 DP,\(f_i\) 考虑用总数减去有 \(\texttt{bordor}\) 的串个数,后者枚举最小 \(\texttt{border}\) 计算。

\(v\) 的前缀积为 \(s\)\(s_i^{-1}\)\(s_i\) 的逆元,则有

\[f_i=s_i-\sum_\limits{j-1}^{\lfloor i/2\rfloor}f_js_{i-j}s_j^{-1} \]

这个转移像个卷积,于是想到分治 NTT,因为转移一定有 \(j\leq i-j\),所以我们分治的时候,用左面的 \(f_js_j^{-1}\) 和右面的 \(s_{i-j}\) 卷,再转移到对应位置(可能再区间外)。

再减小常数,我们只需要计算出 \([1,n/2]\)\(f\),最后 \(O(n)\) 计算 \(f_n\) 即可,还有,\(l+mid+1>n/2\) 的区间是不用做 NTT 的,因为会转移到范围外。

\(O(n\log^2n)\)\(10^6\),彳亍。

2.14

T1

题意好长...... 不写了。

好喜欢这个题,所以让我复述一下题解

先考虑没有问号的情况,我们维护一个栈,两个两个操作,每次我们可以 :

  1. 将两位依次压入栈中
  2. 将第一位与栈中全部元素合并后,再将第二位压入栈中

栈中的情况可以用一个关于下一个压入元素的函数描述,即 \(F[a,b](x)\) 表示当 \(x=0\) 时返回 \(a\)\(x=1\) 时返回 \(b\)。根据上面两种情况,我们很容易得到当前栈加入两个数后的新栈的情况,这样 \(f_{i,j_0,j_1}\) 表示到第 \(i\) 位,栈的状态为 \(F[j_0,j_1](x)\) 是否可行,状态数为 \(4n\)

加上问号,我们可以考虑 DP 套 DP,把 \(4\)\(f_i\)\(0\) 还是 \(1\) 状压起来,复杂度是 \(16^2n\)

T2

看了两个小时硬是没看出来 SG 函数是啥,我自裁

每个棋子是独立的,总的 SG 函数就是每个棋子的 SG 函数异或和,这很难想到吗?

单个棋子的 SG 函数就是它到子树内距它最远的点的距离(这个倒很容易猜到)。

然后就变成数据结构题了,树剖维护,还有就是看到这种最远距离应该能想到直径,所以把直径拎出来做要容易些,不过依然有不少细节要分类讨论,码了 5.3K,十分舒适。

T3

一眼看好裸的最大权闭合子图

复习了一下建图方式

  • 对所有正权点 \(i\),连边 \(s\rightarrow i\),容量为点权
  • 对所有负权点 \(i\),连边 \(i\rightarrow t\),容量为点权绝对值
  • 原图中所有边也都连出来,容量为正无穷

则有,最大权闭合子图的权值 \(=\) 正点权之和 \(-\ \text{maxflow}\)

这个题有一个问题就是选出的子图不能为 \(\varnothing\),所以我们要依次删掉每个点强制选它,但每次建图跑网络流复杂度不能接受,不过因为每次我们都只改了一条边的容量,所以不用重新建图,只需再残量网络上退流,再重新增广即可。

[NOI2012] 美食节 这个题好像也是,有空看看。

2.16

T1

一个小结论,线性基 \(\mathfrak{B}\) 能表示 \(2^i\) 当且仅当把 \(\mathfrak{B}\) 消成对角基之后的第 \(i\) 行只有第 \(i\) 列为 \(1\)

然后这个题我只会 \(O(\dfrac{n^3\log n}{\omega})\)\(O(\dfrac{n^3}{\omega})\) 的做法没听懂/dk/dk/dk

T2

参考 IOI2022国家集训队论文 彭博《图染色问题初探》

众所周知的四色定理指出,任意一个平面图都可以四染色,然而构造方案却不太容易,不过对平面图的五染色却存在很简单的构造方法。

先证引理

\(\text{Lemma}\):任意一个平面图中一定存在度数小于等于 \(5\) 的点

记平面图的点数为 \(V\),边数为 \(E\),联通块数为 \(C\),把平面划分成的区域个数为 \(F\),由平面图的欧拉定理有 \(E=V+F-C-1\leq V+F-2\)。因为每个平面区域至少由三条边围成,每条边被两个平面区域共享,所以有 \(F\leq \frac{2}{3}E\),两个不等式相加得到 \(E\leq 3V-6\)。所有点的度数之和 \(2E\leq 6V-2<6V\),由抽屉原理,必然存在一个点的度数小于等于 \(5\)

接下来给出五染色构造方案

对于平面图 \(G\),找出一个度数小于等于 \(5\) 的点 \(x\),删去 \(x\) 及与其相连的边,得到平面图 \(G^{\prime}\),我们归纳假设已经构造了 \(G^{\prime}\) 的五染色方案,现在要给 \(x\) 染色。

如果与 \(x\) 相连的点小于 \(5\) 个或者有相同的颜色,那么 \(x\) 可以直接染色,否则,我们记与 \(x\) 相连的点为 \(a_i\ (i=1,2,3,4,5)\)\(a_1\)\(a_5\) 顺时针排列,不妨设 \(a_i\) 的颜色为 \(i\),我们从 \(a_1\) 出发找到所有与其相邻颜色为 \(3\) 的点,再从这些点出发找到与它们相邻的所有颜色为 \(1\) 的点,依此类推,得到一颗颜色交错的树 \(T\),如果 \(a_3\notin T\),那我们可以把 \(T\) 中所有点由颜色 \(1\) 变成 \(3\)\(3\) 变成 \(1\),然后把 \(x\) 染色 \(1\)。如果 \(a_3\in T\),我们再从 \(a_2\) 出发对颜色 \(2\)\(4\) 做相同操作,记得到的交错树为 \(T^{\prime}\),由平面图性质,一定有 \(a_4\notin T^{\prime}\)(因为 \(a_1\)\(a_3\) 的路径和 \(a_2\)\(a_4\) 的路径一定相交),将颜色 \(2\)\(4\) 交换后,我们就可以把 \(x\) 染色为 \(2\)

这样我们就有了平面图五染色的 \(O(n^2)\) 构造算法。

回到这道题,因为所给图的特殊性质,一定存在度数小于等于 \(4\) 的点,我们可以用类似方法构造四染色。

T3

赛时已经想到正解了可惜抱零了,赛后重构一遍代码,码了 5.6K 终于过了/tuu

因为是自己想的,所以不写题解了

2.18

T1 是垃圾题,T2T3 都没听懂,完了。

2.19

T1

我写的题解做法,不过好像写的比别人都长(?)

题意:

给你一个长度为 \(n\) 的序列,初始每个点的颜色都不同,每次操作合并两个颜色,求最短的区间 \([l,r]\) 的长度,使 \([l,r]\) 中包含所有颜色。

\(n\leq 10^5\)

这个题也是,真是太喜欢了

首先肯定想到启发式合并,这样就转化为 \(O(n\log n)\) 个单点修改。

然后,看到颜色种类,就想到了记 \(pre_i\) 表示 \(i\) 前边第一个颜色和 \(i\) 相同的位置。

但这个并不是固定区间的询问,怎么处理,我们非常巧妙地记 \(f_i=\max\{j\ |pre_j<i\}\),这个 \(f_i\) 就是 \(i\) 做左端点时使区间合法的最近的右端点。现在我们看看如何维护 \(f\)

我们每次会修改一个点的 \(pre\)(一定是使 \(pre\) 值变大了),这会使一些点的 \(f\) 值变小。假设我们修改了 \(pre_i\),容易发现受到影响的 \(f\) 一定是满足 \(f_j=i\) 的,而且这些 \(f\) 一定是连续的一段(因为 \(f\) 是单调不下降的),修改之后这一段 \(f\) 会被分裂成若干段。我们用线段树维护 \(f\),我们在线段树上二分找出满足 \(f_j=i\) 的区间,然后暴力地一段一段修改即可(区间赋值)。这样的复杂度是正确的,考虑最多会产生 \(n\) 个段,而每次操作最多会造成一次两个段的合并,所以这样的区间修改总共只有 \(O(n\log n)\) 次。

还有一个问题,如何求出新的 \(f\),也就是说如何求最大的 \(j\) 使 \(pre_j<i\),考虑再开一个线段树维护 \(pre\) 及其后缀最小值,这样就可以线段树上二分求出 \(f\)

最后还有一个小问题,并非所有的 \(f_i-i+1\) 都能作为答案,设 \(p\) 是最靠后的满足 \([p,n]\) 包含所有颜色的位置,那么答案应该是 \(i\in[1,p]\)\(f_i-i+1\) 的最小值,\(p\) 随着不断修改操作是单调的,直接一个指针维护就好了。

这样就以 \(O(n\log^2n)\) 的复杂度做完了!

T2

\(n\) 个选手编号 \(0\)\(n-1\),初始时,有一个数字 \(x=0\),选手 \(0\)\(n-1\) 依次选择是否进行操作,选手 \(i\) 进行操作可以将 \(x\) 变为 \((x+a_i)\bmod n\)。最终的 \(x\) 就是胜者的编号。一个选手进行操作当且仅当他能获胜,且不进行操作无法获胜

序列 \(a\) 最初给定,之后 \(q\) 次单点修改,每次你要求出胜者编号。

\(n\leq 3\times 10^5\)

\(p_i=(i-a_i)\bmod n\),因为进行操作的人只会令 \(x\) 变成他自己,所以 \(p_i\geq i\) 是无用的,从 \(i\)\(p_i\ (p_i<i)\) 连边,形成一个内向树森林。

\(f_i=0/1\) 表示若当前 \(x=i\)\(i\) 能不能赢,则有 \(f_i=1\) 当且仅当 \(\forall j\in son(i),f_j=0\),这样树形 DP,最后 \(0\) 号节点编号最小的等于 \(1\) 的儿子就是胜者,若没有,答案就是 \(0\)

带上修改操作,我们就在 LCT 上动态 DP 就可以了,重儿子的转移可以写成 \(g(x)=kx+b\) 的形式(\(k,b\) 适当地取 \(0,1,-1\))。

23 号也有一个 LCT 做的动态 DP,其实写起来感觉差不多。

T3

给你 AC 自动机的 trie 树和 fail 树(根不确定),请你构造出一个符合条件的 AC 自动机。

\(n\leq 3\times 10^5\)

题解垃圾 \(O(n\log n)\) 做法也没看懂,实际上做到 \(O(n)\) 还是比较简单的说。

先假定确定了根怎么做(之后再说怎们找根)

考虑 fail 树,根节点每个子树显然是一个相同的字符,所以直接给每个点标好字符,(一些显然不合法的情况要判掉,比如 fail 边从 trie 上深度浅的点指向深的点)。

然后要检查 \(x\) 的 fail 边指向的点是否是从 \(fa_x\) 开始跳 fail 边第一个遇到的有和 \(x\) 相同字符孩子的点。我们在 fail 树上 dfs,在过程中维护 \(mp_c\) 表示上一个遇到的有 \(c\) 孩子的点,这个很好在 dfs 以及回溯过程中维护。还有一些情况比如 trie 树上有一个节点两个孩子被赋上了相同字符也要判掉。

现在我们考虑怎么找根,如果两点 \(u,v\) 之间既有 trie 边又有 fail 边,那就说明当前点对应的字符串有长度为 \(len-1\) 的 border,那它的循环节就是 \(1\),也就是说,所有这样的公共边构成从边出发的一条条链(一个爪子形),度数大于 \(2\) 的点就是根。

如果所有公共边构成的是一条链,我们考虑链上一个点 \(x\) 在 trie 树上的邻居,它代表形如 \(\texttt{aaa...ab}\) 这样的串,从它出发跳 fail 边,回到链上,假设跳到了链上的点 \(y\),那么 \(y\) 代表的要么是 \(\texttt{b}\),要么是空串,所以根节点一定是 \(y\)\(y\) 在链上的邻居,逐个检查这三个点即可。

这样就做完了!

2.21

今天题相对来说简单多了啊

T1

题意很容易转化成求 LIS 以及哪些位置在所有可能的 LIS 中。从两边分别 DP 并统计方案数,对每个位置检查其两侧的方案数乘积是否等于总方案数(可能会很大,记得取模)

想到 DAG 必经边的经典做法,这个题就很容易想到了。

T2

题意

一棵 \(n\) 个节点的树,每个点可以填一个 \([l_i,r_i]\) 中的整数,需满足相邻两个节点上的数互质。对每个点求其在所有合法方案中上面的数之和。

\(n\leq 50,l_i\leq r_i\leq 50000\),对 \(10^9+7\) 取模。

直接 DP,\(f_{x,i}\) 表示点 \(x\)\(i\) 在其子树内的方案数,转移就是

\[f_{x,i}=\prod\limits_{y\in son(x)}\sum\limits_{j=1}^m [i\perp j]f_{y,j} \]

(这里忽略了 \(l_i,r_i\) 的限制,\(m\) 为值域,具体实现时把不在 \([l_i,r_i]\) 范围内的 \(f_i\) 设为 \(0\) 即可)

直接莫反

\[\sum\limits_{j=1}^{m}[i\perp j]f_{y,j}=\sum\limits_{j=1}^m f_{y,j}\sum\limits_{k|i,k|j}\mu(k) =\sum\limits_{k|i}\mu(k)\sum\limits_{k|j,j\leq m} f_{y,j} \]

后面这一大坨都可以 \(O(m\log m)\) 处理出来,这样整个 DP 以此就是 \(O(nm\log m)\) 的。

对每个点求答案,换根 DP 就可以。

还有,关于换根的写法,我们可以记录每个点孩子前缀和后缀的 DP 值,这样换根的时候就避免了减去贡献,有的时候会简单很多。

T3

转化后的题意大概是给一个括号串,区间询问,求区间内最长的合法括号序列。

\(n\leq 10^5,m\leq4\times 10^6\)

把左括号看作 \(-1\),右括号看作 \(+1\),前缀和之后就是一个若干山峰状的序列,就是求区间内注水,形成的最长连续水面长度(非常形象)

首先能想到 \(O(n\sqrt m)\) 的回滚莫队。

然后还有一个做法是倍增,记 \(r_i\) 表示 \(i\) 右面第一个比它大的位置,\(l_i\) 同理,答案一定是一个区间 \([i,r_i-1]\)\([l_i+1,i]\)。我们倍增地跳 \(l\)\(r\),就可以在线 \(O(\log n)\) 单次询问了。

稍微想想好像也能做到 \(O(1)\) 单次询问。总之都可以通过。

2.23

T1

容易得到 DP

\[f_x=\sum\limits_{y\in son(x)}\max\{f_y,1\}-[\prod\limits_{y\in son(x)} f_y=0] \]

DP 选的根节点必须度数大于等于 \(3\),否则答案就是 \(1\)

加上 Link,cut 操作,考虑在 LCT 上维护动态 DP,一个节点 \(x\) 从重儿子的转移可以写成分段函数

存在轻儿子 DP 值为 \(0\)

\[g_x(val)=\begin{cases}s+1&val=0\\val+s&val>0 \end{cases} \]

不存在

\[g_x(val)=\begin{cases}s&val=0\\val+s&val>0 \end{cases} \]

其中 \(s\) 是所有轻儿子的 DP 结果。

这个分段函数是容易复合的,所以就可以做了(动态 DP 能维护的奇怪东西增加了!)

几个实现细节:

  • 考虑有换根操作(链翻转),所以维护一个从上到下的复合和一个从下到上的复合,reverse 的时候直接 swap 两者即可
  • 为了得到一个实链顶端的 DP 值,我们发现给整个链上的函数代入 \(0\) 是不对的,所以我给维护的函数加了一段,代入 \(-1\) 得到的是链顶的 DP 值
  • \(x\) link 到 \(y\) 上的时候要先 access 一下 \(y\),否则上面虚边的信息都错了(调了好久)

T2

原题:https://blog.csdn.net/weixin_45313881/article/details/104032690

所以就不写题解了,这道题还是很好的。

能不能用这道题解法求边三联通分量?

2.27 Update:好的,A 掉了洛谷模板题,看来是能的 https://www.cnblogs.com/sapphire162/p/15941274.html

T3

寄吧题,毫无难度只需大力分类讨论去构造。(但我也没切,好像没资格这么说)

posted @ 2022-02-17 10:09  iMya_nlgau  阅读(77)  评论(1编辑  收藏  举报