做题(部分)笔记(From 4.11)
4.11 开始的做题笔记
CF468C Hack it!
特别妙的一个思维题。
对于 \(x\) 和满足 \(10^d\ge x\) 的 \(d\),我们有 \(f(x+10^{d})=f(x)+1\)。由于 \(x_{max}=10^{18}\),我们这道题取 \(d=18\) 即可。设 \(t=10^{18}\),\(p=\sum_{i=1}^{t-1}f(i)\)。
所以我们取 \(l=q-p, r=t+q-p-1\) 的时候可以取得解。
至于怎么计算 \(q\),有很多方法,最终得到 \(q=81\times 10^{18}\)。
https://codeforces.com/contest/468/submission/112617719
P6114 【模板】Lyndon 分解
Lyndon Word:自己为自己所有后缀中字典序最小的字符串。
Lyndon 分解:将一个串拆分成若干个 Lyndon Word,且前一个子串比后一个子串字典序更大。
Lemma:
- 对于两个 Lyndon Word \(S,T\),若有 \(S<T\),则 \(ST\) 为 Lyndon Word。
- Lyndon 分解具有唯一性和存在性
- 对于字符串 \(S\) 和字符 \(C\),若 \(SC\) 是 Lyndon Word 的前缀,则对于字符 \(D>C\),有 \(SD\) 为 Lyndon Word。
性质:
- Lyndon Word 没有长度 \(<|S|\) 的 border
- \(s\) 是 Lyndon Word 等价于 \(s=uv\) 且 \(u<v\) 且 \(u,v\) 是 Lyndon Word(即 Lemma 1 的必要性也存在)
Duval 算法
维护三个变量 \(i,j,k\)。
- \(S[1,i-1]=s_1s_2\dots s_p\) 是已经固定的分解。即 \(s_1s_2\dots s_p\) 构成了一个 \(S[1,i-1]\) 的 Lyndon 分解,且这个 Lyndon 分解出现在完整串的 Lyndon 分解。
- \(S[i,k-1]=t\dots t+v\) 是没有固定的分解。其中 \(t\) 是一个 Lyndon 串,且 \(v\) 是 \(t\) 的非空真前缀,且 \(s_p>S[i,k-1]\) (显然)。
设现在新来的字符为 \(S_k\)。\(j=k-|t|\)。
- \(S_k=S_j\): \(k:=k+1, j:=j+1\)。
- \(S_k>S_j\): 则 \(v+S_k\) 为 Lyndon Word。则 \(S_{p+1}=S[i,k]\) 为新的 Lyndon Word。
- \(S_k<S_j\): 则 \(t\dots t\) 的 Lyndon 分解一定是若干个 \(t\)。
复杂度 \(O(n)\) (好像和 \(i\) 与 \(k\) 的移动相关)。
https://www.luogu.com.cn/record/49401937
P3354 [IOI2005]Riv 河流
课上的题目。考虑”承诺“型 DP。\(f(u,j,k,0/1)\) 代表考虑 \(u\) 及 \(u\) 的子树,用了 \(k\) 个伐木场并承诺最近的祖先伐木场是 \(j\)(且 \(u\) 是否建造的状态为 \(0/1\))。
考虑特殊的树上背包 DP 转移
还有之后需要再更新一遍
https://www.luogu.com.cn/record/49450699
P5829 【模板】失配树
字符串 \(s\) 的 border \(i\) 满足 \(s\) 的长 \(i\) 的前后缀相等。我们设 \(s\) 的 \(\text{max border}\) 表示 \(\text{border}\) 集合中最大(长)的一个。显然,\(\text{max border}\) 即 KMP 中的 \(\text{next}\)。(因为 KMP 的第一部分就是一个自我匹配寻找 \(\text{border}\) 的过程)。
如何求出 \(\text{border}\) 集合?我们有性质 \(\text{border}(s)=\text{border}(s[1,next_s]) \cup next_s\)。这样,我们不断地跳 \(next\) 就能求出一个串的 \(\text{border}\)。
有没有办法求出所有前缀的 \(\text{border}\) 呢?显然是可以的。由于一个前缀的 \(\text{border}\) 依赖于这个前缀的一个前缀的 \(\text{border}\),我们可以建立一种树的关系。考虑 \(next_i\) 作为 \(i\) 在这样的树上的父亲节点(感觉是不是可以叫 border tree),那么前缀 \(s[1,i]\) 的 \(\text{border}\) 集合就为点 \(i\) 的所有祖先节点。
题目要求两个前缀的最长公共 \(\text{border}\)(\(LCB\)?),显然这个最长公共 \(\text{border}\) 就是它们两个前缀在这棵树上的除自己外的 LCA。
https://www.luogu.com.cn/record/49470329
P1368 【模板】最小表示法
最小表示法,即求字符串的所有循环同构中,字典序最小的循环同构。
对于这种循环同构问题,我们可以考虑将这个字符串破环为链(把自己接在自己后面),然后 Lyndon 分解。我们找到一个首位 \(\le n\) 的 Lyndon 串的起始位置,显然处在最后的那个 Lyndon 串即为解。
https://www.luogu.com.cn/record/49472066
P3530 [POI2012]FES-Festival
先差分约束建图。我们考虑拆强连通分量。两个分量之间显然只会存在单箭头关系,所以求出拓扑序后,后面一个分量的所有点比前面的分量的所有点集体大 \(n\) 就能保证两个分量之间没有任何相同的数。设单个分量内的答案为 \(ans_i\),则 \(Ans=\sum ans_i\)。考虑单个分量内如何计算。我们差分约束要求出分量内所有点对的最短路径,然后取其最大值然后再 \(+1\) 即可。原因比较简单,因为本题中边权的绝对值都 \(\le 1\),所以最短路径最大值 \(+1\) 后就是所可能的最多不同的成绩数量。
https://www.luogu.com.cn/record/49483223
CF1511E Colorings and Dominoes
显然只有竖着的蓝色连续段或者横着的红色连续段会对答案产生贡献,且红色和蓝色的贡献是独立的。我们考虑用算贡献的方法计算每条单链的贡献。我们设 \(f_i\) 表示连续 \(i\) 格的白色格子产生的贡献。假如我们考虑是横着的一段。决策为 \(i\) 是红色还是蓝色。如果 \(i\) 是蓝色,那么对 \(f_i\) 的贡献为 \(f_{i-1}\)。如果 \(i\) 是红色且 \(i-1\) 是蓝色,那么贡献是 \(f_{i-1}\)。如果 \(i-1\) 也是红色,那么我们放上骨牌,然后贡献为 \(f_{i-2}+2^{i-2}\)。
设白点总共有 \(c\) 个,则 \(ans=\sum f_{l}\times 2^{c-l}\)。
https://codeforces.com/contest/1511/submission/113085175
P3623 [APIO2008]免费道路
题意:给定一张有黑边和白边的图。求一张 \(n\) 个点的生成树满足有 \(k\) 条黑边。
首先确定一个比较感性的理解。如果我们可以用黑边比 \(k\) 条黑边少的方案(前提是有足够的黑边),那么我们就一定可以补救回来;否则我们无论怎样都无法补救。所以我们先把白边弄到生成树中,然后再加黑边,求出哪些黑边是一定要加入的。如果一定要加入的黑边数量 \(>k\),那么就是无解。否则我们先把这些一定要加的黑边加入,然后把黑边的数量加到 \(k\),剩下的边加白边即可。
https://www.luogu.com.cn/record/49529075
AGC001C Shorten Diameter
http://www.xmoj.tech/problem.php?cid=3442&pid=0
考虑枚举最终的树的中心。然后分类讨论。\(k\) 为偶数时,中心在一个点上,所以所有距离它 \(>\frac{k}{2}\) 的都要删掉;否则中心在两个相邻的点上,所有距离它们 \(>\frac{k-1}{2}\) 的点都要删掉。
https://www.luogu.com.cn/record/49598135
P4429 [BJOI2018]染色
http://www.xmoj.tech/problem.php?cid=3442&pid=2
首先考虑每个连通块。如果不是二分图,那么 \(n\) 个 \(\{A,B\}\) 就能卡死。然后我们把叶子节点全部给删除。然后考虑如果存在两个没有边的交集的偶环,显然这是不可能的,因为我们可以做到使得两个偶环之间的路径中出现矛盾,即 \(m\ge n+2\) 时是不行的。如果 \(m\le n\),显然是可以的。然后我们的连通块可以简化成 \(s\to t\) 的三条路径,其中 \(s,t\) 为唯二的度数为 \(3\) 的点。设三条路径的长度为 \((x,y,z)\)。我们可以发现,如果 \((x,y,z)\) 是不可行的,那么 \((x+2,y,z)\) 也是不可行的。我们枚举一下,发现只有形如 \((2,2,2k)\) 的才是有解的。
https://www.luogu.com.cn/record/49606637
AGC001F Wide Swap
http://www.xmoj.tech/problem.php?cid=3442&pid=1
考虑原排列的逆置换 \(Q\)(\(Q_{P_{i}}=i\)),题目条件转化成对于相邻且差 \(\ge K\) 的 \(Q_{i,}Q_{i+1}\)可以交换。于是,我们发现如果对于两个 \(|Q_i-Q_j|<K\),那么它们永远都不会交换。\(Q\) 可以通过交换变成的 \(Q'\) 一定满足对于原本 \(|Q_i-Q_j|<K\) 的 \(Q_i,Q_j\) 的相对位置不变,并且有满足上述条件的 \(Q'\) 一定是可以从 \(Q\) 通过操作变成的。
所以我们循其本,重新考虑原题中的 \(P\)。原题条件转化为求一个字典序最小的 \(P'\),满足对于的距离 \(<K\) 的 \((i,j)\),\([P_{i}<P_{j}]=[P'_i<P'_j]\)。
这种题目可以考虑根据 \(P\) 建一个 DAG。如果 \(|i-j|<K\) ,就从小的向大的连一条边。然后我们需要求该 DAG 的最小字典序的拓扑序。复杂度 \(O(nk)\)。
这个图其实非常的特殊,可以直接用数据结构做。一个点入度为 \(0\),代表它在 \((i-K,i+K)\) 区间中是未被删除的 \(P\) 最小的点。我们先把这些点找到,然后扔进一个以节点编号为权值的堆中。一个点一旦被删除,那么区间内所有未被删除的点的度数都需要 \(-1\)。然后我们找出区间内最小的点(注意左半区间和右半区间要分开找,因为这两个区间可以存在两个自己连边区间没有交集的点),如果可以那么就塞进堆中。
线段树要维护:区间最小值以及位置。支持单点修改和区间查询。
https://www.luogu.com.cn/record/49699977
P2619 [国家集训队]Tree I (wqs 二分)
考虑 Kruskal 一下最小生成树。如果生成树白边数量 \(<need\),那么我们就让白边每条边加一些边权;否则就减去一些边权。这样我们就能凑齐 \(need\) 条白边。设我们加边权的权值为 \(k\),考虑二分 \(k\)。答案为 \(ans=need\times k\)。
显然有些时候存在加上一些边权 \(p\) 后超过 \(need\),但 \(p-1\) 时小于 \(need\),则我们考虑此时一定只是存在一些白边黑边边权相等,我们把一些白边换成黑边即可,所以答案就是加上 \(p\) 那时候的情况减去 \(need\times k\)(注意是 \(need\) 而非超过的那个数)。
https://www.luogu.com.cn/record/49860991
P3639 [APIO2013]道路费用
考虑对于新边集最后在生成树上的的边集 \(E\),我们可以把这 \(|E|\) 条边加入生成树 \(T\) 后再对旧边做 Kruskal,求出这种情况下的最小生成树的其他边。我们对于不在生成树上的边 \(e\not\in T\),一定有 \(T\) 上的路径 \((u,v)\) 上所有边的边权都 \(\le w_e\)。这样我们就能确定每一条 \(\in E\) 的边的边权最大值。然后树形 DP 一下每条边会被多少人经过。这个算法是 \(O(2^k nm)\) 的。
我们发现对于不同的 \(E\),其 \(T\) 很大一部分是一样的,还有一些旧边根本不会被用到。我们考虑在一开始的时候(\(E=\) 所有新边的集合),计算出在这种情况下(用尽新边)哪些旧边是在 MST 内的。显然这些边无论 \(E\) 是什么,都会包括在 MST 内,设这个集合为 \(S_0\)。我们将 \(S_0\) 中的边进行缩成一个点。现在总共有 \(k+1\) 个点。我们在缩点过后的旧边做一次 MST,会得到 \(k\) 条边,设其为 \(S_1\)。容易证明,所点过后的图的旧边中只有 \(S_1\) 中的边才可能成为 MST 上的边。所以我们将边数缩到了 \(O(k)\)。复杂度 \(O(2^kk^2+m\log m)\)。
https://www.luogu.com.cn/record/49880244
AGC005F Many Easy Problems
考虑每个点算贡献。一个点贡献存在两种情况,第一种为其被选择在 \(S\) 中,另一种为其被不被选择在 \(S\) 中。第一种情况的贡献为 \(\binom{n-1}{k-1}\),第二种情况的贡献为 \(\binom{n-1}{k}-\sum_{v\in son_u} \binom{sz_v}{k}\)。
设 \(f_k\) 为答案,则有
可以 \(O(n^2)\)。(上述为想到的部分)。
考虑我们继续以 \(sz_v\) 算贡献。设 \(c_i\) 代表 \(sz_u=i\) 的 \(u\) 数量,则有
看上去很卷积?我们设有 \(F_i=c_i\times i!, G_i=\frac{1}{i!}\),则可以得到一个差卷积
模数是 NTT 模数(原根为 5),NTT 即可。
https://www.luogu.com.cn/record/49891567
AGC005E Sugigma: The Showdown
(红色象征了gcd的游击战略(雾)考虑什么时候先手一定可以不被后手追到。我们可以形象地联系生活场景(指自己在教室追/被追),一定是存在一条红边 \((x,y)\),使得先手只要不停地在 \((x,y)\) 徘徊,后手永远都没法追上。这样需要满足蓝树上 \((x,y)\) 路径的距离 \(>2\)。只要先手不断往那条边跑,如果能跑到,那么后手就追不上先手。我们称这样的红边为游击边。
由于是树,走的路径很具有局限性。我们发现,对于一个节点 \(u\),它能在不被捉到的情况下被先手达到当且仅当 \(u\) 到红色先手出发点的距离小于 \(u\) 到蓝色后手出发点的距离。我们可以通过 dfs 就能求出哪些点是可以被先手到达的,然后判断这些点的红色导出子树存不存在那样的游击边。如果可以到达游击边,\(ans=-1\)。否则就是这些点中离后手出发点最远的那个点,先手跑到那里去等死就行了,容易证明这是最佳方案。
https://www.luogu.com.cn/record/49913012
P5882 [CTSC2015]misc
考虑用计算贡献的方法做。
对于每一个点 \(s\),建出以其为源点的最短路 DAG (将边反向,因为 DP 的顺序为拓扑逆序),然后 DAG 上 DP。\(\sigma\) 在求最短路的时候就能算。设 \(f_u=\sum_t\frac{a_t\sigma_{tv}}{\sigma_{st}}\)。转移为将 \(\sigma_{u,t}=\sigma_{u,v}\times \sigma_{v,t}\) :
https://www.luogu.com.cn/record/49931624 (见证 spj 崩盘现场)
P3538 [POI2012]OKR-A Horrible Poem
一个循环节 \(s[1,k]\) 满足它一定是一个周期且它的长度被原串长度整除。它是一个周期等价于 \(s[k+1,n]\) 是 border。(所以如果没有被整除这个条件,那么这题就成了区间 border 问询,很复杂)。
所以,利用 hash,我们可以通过判断是否为 border 的方式 \(O(1)\) 判断是否为循环节。我们想要得到所有可能成为最小循环节的前缀。我们发现如果我们一直尝试除以最大的素因数,那一定可以得到最小的循环节。这是因为我们发现如果 \([1,k]\) 是一个循环节,那么如果 \([1,k]\) 不是循环节,则 \(1[k/p]\) 必然也不是循环节。由于在数据范围内一个数的质因数个数很少(\(O(\log)\)),所以可做。我们在线性筛的时候维护一个数组 \(pr_i\),代表其最小素因数。然后不断地除以 \(pr\) 就可以得到其所有素因数。复杂度 \(O(q\log n)\)。
https://www.luogu.com.cn/record/49949623
P5444 [APIO2019]奇怪装置
考虑 \((x,y)\) 的循环节。设 \(t_1,t_1+kB\) 满足两个时间点的 \(x\) 相同,则有
所以我们找到了循环节,接下去只要区间覆盖即可。
https://www.luogu.com.cn/record/49967523
P3573 [POI2014]RAJ-Rally
很妙……
我们将图拓扑排序后,点分成两部分。设现在点分成两部分(设按照拓扑序为 \(1...n\))\([1,x], [x+1,y]\)。其中左边的部分是尚未计算删除之后的答案的,右边部分是计算过了删除之后的答案的,并且因为是按照拓扑序,所以连接两边的边一定是从左到右的,\(x\) 连出去的边也一样。
设 \(d_s(u)\) 代表从起点到 \(u\) 的最长路,\(d_t(u)\) 代表从 \(u\) 到终点的最长路。图中最长路可能有三种:左边部分内部(\(\max_{1\le u\le x} d_s(u)\)),右边部分内部 \(\max_{x<u\le n} d_t(u)\),以及左边到右边 \(\max_{u\to v} d_s(x)+1+d_t(v)\)。我们考虑把 \(x\) 删除会发生什么。我们会删除掉一个 \(d_s(x)\),和所有满足 \(x\to v\) (\(v\) 也是右边节点)的 \(d_s(u)+1+d_t(v)\)。然后更新答案后,我们就要把 \(x\) 移到右边,即添加 \(d_t(x)\),和所有满足 \(v\to x\)(\(v\) 是左边节点)的 \(d_s(v)+1+d_t(x)\)。整个过程维护了加入删除和查询最大值,用一棵权值树即可。
复杂度 \(O(m\log m)\)。
思维突破口在:首先 DAG 可以考虑拓扑序,然后考虑到我们希望能让最长路径的改变尽量只和 \(x\) 有关,又因为拓扑序满足了可以将图分成两段,并且很好地将 \(x\) 分离了开来。
https://www.luogu.com.cn/record/49994971
P5666 [CSP-S2019] 树的重心
考虑本题求和可以转化成贡献形式(trick!),考虑每个重心在多少个分裂子树中会出现。我们把树用一个重心作为根来看。设 \(u\neq root\),我们设 \(s_u=\) 子树大小,\(g_u=\max_{v\in son_u}s_v\)。我们设考虑 \(u\) 能走作为分裂子树的重心。设我们割掉的是 \((x,fa_x)\) 这条边。设 \(P_x=\) 割掉 \((x,fa_x)\) 后 \(x\) 所在的连通块的大小。则 \(x\) 必须满足 \(x\) 不在 \(u\) 的子树中且 \(n-P_x-s_u\le \frac{n-P_x}{2}\) 且 \(g_u\le \frac{n-P_x}{2}\)。
化简可得
- \(x\) 不在 \(u\) 子树中
- \(P_x\in [n-2s_u,n-2g_u]\)
考虑动态维护一个存储了 \(P\) 的权值树状数组。我们每次 dfs 的时候从 \(u\) 换到 \(v\),改变的 \(P\) 只有 \(P_u\)。\(P_u\) 从 \(s_u\) 变成了 \(n-s_v\),仅此而已。我们每次询问全局的有多少处于 \([n-2s_u,n-2g_u]\) 可以通过树状数组求得。现在我们要排除掉 \(x\) 在 \(u\) 子树内的情况。子树的话,一个子树在 dfs 序上相当一个区间,也就是两个版本相减。子树的信息相当于回溯时树状数组的版本减去刚进来时树状数组的版本。(如果暴力一点那么直接线段树合并、dsu on tree 和可持久化线段树)。
然后我们要计算 \(root\) 作为重心出现了多少次。考虑对于 \((u=fa_v)\),割掉这条边后能否让 \(root\) 成为重心。如果 \(v\) 处于 \(root\) 的儿子的最大子树中,那么我们设 \(root\) 的次大儿子 \(y\),最大儿子 \(x\),则需要有 \(n-2s_y\ge s_u\),否则是 \(n-2s_x\ge s_u\)。
由于可能需要加入和计算入 \(0\),所以树状数组集体右移一位。
https://www.luogu.com.cn/record/50063984
ARC097D Monochrome Cat
首先从叶子节点向上删除黑点,因为它们永远都不用被走到。
现在我们假设树的所有叶子结点都是白点。然后如果我们从 \(u\) 走到 \(u\),那么需要走 \(2\times (n-1)\) 条边。此时每个点都经过了 \(\deg\) 次,存在一些点是白色的。我们在白色的点上多停留一次,这样所有点都成为黑色了。然后我们其实并不需要走一个回路。我们从 \(u\) 出发然后走到 \(v\) 结束即可。所以我们需要选择这样的一条路径不去走它。设 \(w\) 为 \((u,v)\) 上的点。如果 \(w\) 在走完回路后是白色的,那么我们如果不走 \((u,v)\),我们不仅可以节省不用多走一次这个点,还能省一次停留在这个点改变颜色的时间,一共省2步。如果 \(w\) 在回路后是黑色的,我们尽管节省不用多走一次这个点,但是我们还要多加在这里停留一次改变颜色,所以并没有省。所以我们要找到白色节点最多的一条路。DP 即可。
https://www.luogu.com.cn/record/50207855
CF1515E Phoenix and Computers
在巨佬的点播下推出了最终解法成功上分然后成功打破0输出局面。
首先发现最终手动打开的电脑一定组成了很多连续段,且各个连续段间有一个自动打开的电脑。
对于一个长 \(x\) 的连续段,打开的方式有 \(2^{x-1}\) 种(从中间往两边推进)。各个连续段之间互不影响,只是内部的步数是段内自己钦定的。所以假设一共有 \(k\) 段,每段为 \(x_1,x_2,\dots,x_k\),答案即为
对这个求和可以 DP。设 \(f(i,j)\) 表示前 \(i\) 台电脑,分了 \(j\) 段(留下 \(j-1\) 个自动打开的位置)。
https://codeforces.com/contest/1515/submission/114950103
CF1515F Phoenix and Earthquake
首先一个沥青数量 \(>x\) 的城市和别的城市接起来,肯定不会变坏。我们不断地将沥青最多的城市和别的城市接起来。
还有一种有意思的解法。我们发现任何一棵树都是可以的(只要沥青总量都够),所以我们搞出一个生成树,然后从叶子向上玩。如果叶子的沥青+父亲的沥青数量 \(<x\),那么就放最后合并。
https://codeforces.com/contest/1515/submission/114983671
CF1515G Phoenix and Odometers
考虑由于是回路,一个点走的回路一定在包含的强联通分量上。所以我们把每个强联通分量搞出来后,只用考虑对于一个强联通分量的情况。
首先是一个操作。如果 \(u\to v\) 存在长 \(w\) 路径,那么 \(v\to u\) 就可以存在长 \(-w\) 的路径。我们从 \(v\) 开始。走沿 \(u\to v\) 方向走 \(P\) 次回路然后最后一次回路少走 \(u\to v\) 那条边使其停在 \(u\) 上,就能走出一条 \(v\to u\) 的长 \(-w\) 的路径(模意义下)。
然后考虑回路是怎么样的。我们的每个 \(u\) 出发的回路可以抽象成 \(u\to 环\to ...\to 环 \to u\)。由于两个点可以总共花费 \(0\) 来回走一趟,所以这个回路长度相当于所有走的环的长度和。设所有环的长度分别为 \(l_1,l_2,...,l_k\),我们相当于要凑出一组 \(a\) 使得 \(\sum a_il_i\equiv -s\pmod t\)。这是一个简单经典的同余方程求解问题。我们设环长度的 gcd 为 \(g\),有解当且仅当 \(\gcd(g,t)\mid s\)。
我们只需要统计极小环即可。所以我们在找返祖边的时候记录一下就行了。
https://codeforces.com/contest/1515/submission/115043828
AGC009D Uninity
设我们每个点的 uninity \(d_i\)。首先我们发现答案最多为 \(\log\) (点分治树)。然后有个性质,发现对于点分树(最终的树)上 \(d\) 相等的两个点在原树上的路径上必存在一个 \(d\) 更大的点。这样我们提一个根后,称那些还没有存在 \(d\) 更大的点的路径连接的点为未盖点,则 dp 设 \(f(u,i)\) 表示 \(u\) 子树中,\(d\) 为 \(i\) 的未盖点数量。我们贪心地求得 \(u\) 的能取到的最小的 \(d\)。首先这个 \(d\) 必须满足 \(\forall x>d, f_{u,x}<2\),否则子树中就会存在两个 \(d=x\) 的点未盖点。还有,\(d\) 需要满足 \(f_{u,d}\neq 1\),否则那个同样 uninity 为 \(d\) 的点和点 \(u\) 就会成为未盖点。最后更新一下 \(f\) 即可。
https://www.luogu.com.cn/record/50226309
AGC009E Eternal Average
这道题很强。考虑将修改的过程记录下来,形成一个 k 叉树,0 和 1 为叶节点。设一个点的深度为 \(d\),那么它对根的贡献就是 \(a_ik^{-d}\)。所以设权值为 1 的深度为 \(x_i\),权值为 0 的点的深度为 \(y_i\),根节点即为 \(\sum k^{-x_i}\)。且我们需要保证 \(\sum k^{-x_i}+\sum k^{-y_i}=1\)(如果所有叶节点权值都为 1 那么根也为 1)。只要满足这个条件,我们就可以构造出这样的树。所以题目变成了求满足 \(Z\) 和 \(1-Z\) 都能表示成 \(\sum k^{-x_i}\) 形式的 \(z\) 的个数。我们发现 \(k^{-x}\) 比较难处理,考虑把 \(z\) 写成 k 进制小数 \(Z=\sum_i z_i\times k^{-i}=(\overline{0.z_1z_2\dots})\)。
如果不考虑进位,那么\(\sum z_i=n\)。如果进位,那么 \(\sum z\) 就要减少 \(k-1\),所以,但是 \(\mod k\) 的值还是不变,所以我们有 \(\sum z_i\equiv n\pmod {k-1}\)。然后再考虑 \(1-z\) 需要满足的情况。同样的,我们有 \(1+\sum_{k-1-z_i}\equiv m\pmod {k-1}\)。
可以直接 DP。设 \(f(i,j,0/1)\) 表示这是第 \(i\) 位小数,\(\sum z=j\),且有没有后缀 0 (小数不能有后缀 0)。
用前缀和优化一下即可。
https://www.luogu.com.cn/record/50227932
AGC003 BBuBBBlesort
我们可以把一个数用第二个操作不停地转到自己应该在的位置。存在一些情况使得其转不到,这是因为用第二种操作不能改变自身奇偶性,所以需要用第一个操作。所以我们找到目标位置和自己位置奇偶性不同的点,然后除以二即可。
https://www.luogu.com.cn/record/50228411
AGC006E Rotate 3x3
感觉这种题比较恶心。
首先无论怎么转,一列的数必然是连续的,且从上到下或者从下到上为 \(3k-2,3k-1,3k\)。我们给每一列搞个标号 \(k_i\),如果没有颠倒那么是正数,否则是负数,且绝对值为上述的 \(k\)。每次转相当于三列同时取反且两列互换。
其次无论怎么转,列的奇偶是不会变的。所以我们可以奇偶分开讨论。
然后我们通过一系列研究发现我们可以通过一系列操作让两个同奇偶的列同时取反。所以我们先去弄列的顺序再去判断正负的问题即可。
这一系列的操作为:设 \(to_i\) 表示第 \(i\) 列原本应该在的位置。我们不停地去 swap \(to_i,to_{to_i}\),直到让 \(to_i=i\) 位置,即答案最终的位置。奇数每一次 swap 都会造成偶数的负数个数的奇偶性发生改变,偶数 swap 的时候同理。
https://www.luogu.com.cn/record/50231272
AGC006B Median Pyramid Easy
首先我们可以发现最边缘的数(\(1\) 和 \(2n-1\))显然是不行的。
然后我们手动模拟一下。如果处于中间的两个位置\((n,n+1)\) 一旦相同,那么结果一定是这两个位置上的值,相当于它站稳了 C 位,并且能一直保持这两个位置都属于它。显然,让这两个位置相同是所有非边缘的数都可以做到的。我们可以让中间四个数为 \((x+2,x,x-1,x+1)\) 或者 \((x-2,x,x+1,x-1)\)。
https://www.luogu.com.cn/record/50233340
AGC006D Median Pyramid Hard
一个很重要的trick:关于中位数,可以考虑二分它是否大于等于 \(x\)。然后另一个 trick,把所有数以中位数为分界线,小于等于中位数的是 0,其他的是 1。我们模拟一下,发现这相当于 0 和 1 在不断地往中间挤。如果有两个相邻的相同元素,那么它们就不会在中途被分开(被另一个吞并)。所以我们只需要找到哪个会更早一步地达到中间(不被吞并,成为最后的胜利者)。即距离中心最近的一对相邻的相同的项。如果两边不存在,意味着是 0 1 间隔,最后面来的一定可以在最后形成 101 或者 010 的局面,所以应该是最边缘的元素最终会获胜。
https://www.luogu.com.cn/record/50234714
AGC006F Blackout
简化题意:原始是一个有向图。如果有边 \(u\to v, v\to w\),那么 \(w\to u\) 也会有边。考虑对连通分量进行三染色(0->1->2->0)。如果是二分图(左 -> 右),那么就无法有新的边;如果无法染色,那么一定能构成强连通分量,边数为 \(n\times n\);如果恰好能三染色,那么会有三种边(0->1,1->2,2->0),所以为 \(c_0c_1+c_1c_2+c_2c_0\)。
https://www.luogu.com.cn/record/50237273
P4428 [BJOI2018]二进制
经过简单的推导可以发现,区间不满足当且仅当 \(1\) 的个数 \(=1\) 且 \(0\) 的个数 \(\ge 2\),或者 \(1\) 的个数为奇数或者 \(0\) 的个。
这些东西可以用线段树(复杂地)维护。区间内的个数,相当于左区间的个数+右区间的个数+跨区间的个数。
无力继续写了。爬了爬了。
https://www.luogu.com.cn/record/50259428
P5011 水の造题
首先考虑一眼的 DP。我们设 \(f_i\) 表示前 \(i\) 步的取值。(设 \(j\) 前面那个元素就是 \(a_{j-1}\) 了,\(j=1\) 时自动代成 \(k\))
我们有首项 \(f_1=\frac{\sum a}{k}\),于是有答案
https://www.luogu.com.cn/record/50268208
AGC006C Rabbit Exercise
每一轮操作,我们都不断扫+更新一下 \(f_{i}=\frac{(2f_{i-1}-1)+(2f-{i+1}-1)}{2}=f_{i-1}+f_{i+1}-f_{i}\)。
然后妙的操作就来了。我们对 \(f\) 做差分。\(d_i=f_i-f_{i-1}=f_{i+1}-f_i=d_{i+1}, d_{i+1}=f_{i}-f_{i-1}=d_i\)。于是这样的一次操作相当于交换 \(d_{i},d_{i+1}\)。于是这样就可以用置换快速幂去做。
https://www.luogu.com.cn/record/50273532
AGC010C Cleaning
我们发现,一个节点 \(u\) 承担着连接两条叶子\(-u\)的路径使得其组成完整的叶子-叶子路径,还承担着把一些这样的路径往上送,然后和子树外的叶子匹配。我们设 \(f_u\) 代表 \(u\) 要往上送多少路径,且有 \(g_u\) 条路径在 \(u\) 处匹配连接。设有 \(s_u\) 条路径送到了 \(u\) 这里,我们就有 \(2g_u+f_u=s_u, g_u+f_u=a_u\)。解方程得到 \(g_u=s_u-a_u, f_u=2a_u-s_u\)。
好了,我们看一下限制条件。首先,我们有 \(f_u,g_u\ge 0\)。然后,我们必须保证在 \(u\) 处匹配的必然不和自己子树内的叶节匹配。这个用数学语言换一下,\(\max f_v\le \frac{s_u-f_u}{2}=a_u\)。
https://www.luogu.com.cn/record/50360493
AGC007F Shik and Copying String
自己的算法萎了……
我们模拟样例,观察每个可爱的连续的字符区间的靠右的折线。我们发现发现左端点的折线越往右边越优。然后如果右边没有了就往下面走。
我们考虑维护一下左端点折线转折的地方(从上面正确 copy 的位置),动态去求出每一条折线的转折点。从右往左,从上一条折线转移到下一条折线,相当于每一个转折点向左下移一格(紧贴着)。我们用队列维护。
https://www.luogu.com.cn/record/50361571
P3687 [ZJOI2017]仙人掌
如果图不是仙人掌,那么直接输出 0 即可。如果图存在环,那么我们之后加的边肯定不会跨过这个环,所以我们把仙人掌拆分成无环的几个部分(把环给丢掉),形成了几棵独立的树。然后我们考虑加边变成环其实等价于找到几条互相没有交集的路径,然后路径的端点连边,就能构成仙人掌。所以问题转化成了在树上有多少选择若干条互相没有交集的仙人掌的方案数。
我们可以考虑 DP。关于树上路径的覆盖选择问题可以这样设状态 \(f_{u,0/1}\) 表示 \(u\) 及其子树,是否会有一条从 \(u\) 子树生长到祖先的路径。
首先对于 \(f_{u,0}\),我们的每一个儿子节点伸展出来的链都可以选择与其他儿子节点伸展出来的链所匹配。
我们需要一个辅助数组 \(g_i\) 表示 \(i\) 个儿子节点,每个儿子节点可以和别的未使用的儿子节点组成路径或者和根节点组成路径的方案数。我们有 \(g_i=(i-1)g_{i-2}+g_{i-1}\)。
所以 \(f_{u,0}\) 的方案是(\(cs_u\) 代表儿子数量)
然后考虑 \(f_{u,1}\) 的转移。我们要选择出一个儿子节点,它的伸展出来的路径成为 \(u\) 伸展出来的路径,或者我们也可以直接选取 \(u\) 这个点作为伸展出去的路径的起始点。所以我们有
https://www.luogu.com.cn/record/50445685
P5794 [THUSC2015]解密运算
少见自己能做出来的简单题。设 \(a\) 表示题目中给的序列,\(b\) 表示 \(a\) 排序后的值,\(p_i\) 表示 \(b_i\) 在 \(b[1,i]\) 中是第几次出现,\(q_{i,j}\) 表示在 \(a\) 中第 \(j\) 次出现的 \(i\) 的位置。首先我们找到 \(a_i=0\) 的 \(i\) 作为 \(pos\),是答案序列的第一个(\(b_{pos}\)),随后我们让 \(pos=q_{b_{pos},p_{pos}}\)。
https://www.luogu.com.cn/record/50536856
AGC010F Tree Game
对于一个菊花树,我们发现一个根节点 \(u\) 可行当且仅当 \(\min a_{v}<a_u\)。这样先手可以通过让旗子在两点间徘徊而取胜。
对于普通树,我们也一样。如果我们在 \(u\),如果 \(u\) 的儿子中的所有子树内先手必胜点(后手即将在那里做决策的那个点)有 \(\min a_v<a_u\),那么一定可以让他们在两点间徘徊然后先手取胜。