2024.12.12 近期练习
实在是难以相信我竟然又来到了机房训练。
P10141 [USACO24JAN] Merging Cells P
一个简单的 \(dp_{i,l,r}\) 表示最后如果剩下的是 \(i\),当前 \(i\) 所处的区间是 \([l,r]\) 的概率。
区间往外拓展当前仅当当前 \([l,r]\) 区间的和不小于拓展的区间的和。
然而状态数已经达到 \(O(n^3)\),完全无法优化。
注意到初始条件是 \(dp_{i,i,i}=1\),而 dp 是一个路径计数过程,考虑将 DAG 图反置。
也就是原本我们是区间的合并,现在时光倒流,转化为区间的分割来划分子任务。
也就是求从 \([1,n]\) 开始,存在 \([l,r]\) 这样一个区间是被分割的。
考虑区间分割的点 \(p\in[l,r-1]\),是等概率选择的,然后哪边大就贡献到哪边的区间,另一边舍弃。
考虑前缀和优化,维护 \(sum_{l,i}\) 表示左端点为 \(l\),右端点为 \(i\) 时被贡献多少。固定右端点同。
P4437 [HNOI/AHOI2018] 排列
看式子的形式应该是贪心,我们即需要让后面的 \(w_{p_i}\) 尽量大,考虑从后往前填。
那么我们可以得到一个条件就是,要想填 \(a_j\),即 \(a_{p_i}=j\),那么 \(j\) 必须已经被填了。
这非常像一个图论建模。考虑 \(j\) 向 \(a_j\) 连一条边。那么如果不是 DAG 就无解。
如果是 DAG,进一步地其实这就是一棵内向树,考虑从根节点,也就是 \(0\) 号点开始删。
很典是吧,转化为选平均数最小的若干段。取出平均值最小的点 \(x\),然后将 \(x\) 与父亲合并。
合并代表的是,若 \(x\) 父亲被选了,那么下一个一定选的是 \(x\)。然后重复该过程,直到只有一个点。
关于答案的计算,只需要在每次合并的时候累加上 \(w_x\) 乘父亲的大小即可。考虑并查集维护。
这是一个形而上学的问题。
P4654 [CEOI2017] Mousetrap
考虑先给树定根,很显然要定到 \(t\) 这个点。
考虑整个过程是什么样的,老鼠显然最后一直走走到一个叶子节点。
当老鼠被困住的时候,我们可以先堵住不是前往 \(t\) 的所有边,然后再擦除每条去 \(t\) 的边。
而在老鼠走向叶子的过程中,我们可以堵塞其一些道路,我们要堵塞其花费最大代价的道路。
考虑树形 dp 设 \(f_u\) 表示一个子树内的答案,那么 \(f_u=deg_u-1+2nd\max f_v\)。
如果 \(s\) 与 \(t\) 之间只有一条边,那么答案就是 \(s\) 次大的子树代价加上 \(deg_s-1\)。
考虑可以从 \(s\) 往上走再岔进某个子树。这时候比较难算,考虑二分答案 \(v\)。
在往上走的时候,如果有子树的答案超过了当前的 \(v\),就要给他堵住,并使得 \(v\) 减去 \(1\)。
并且,需要堵住的个数不超过当前能用的步数。满足以上的条件 \(v\) 就是合法的。
ARC140D One to One
首先联通块的个数等同于环的个数。考虑拆贡献到每个环。
如果已经存在的环,我们直接加上其贡献。现在问题就是已知有若干棵内向树,要把他们拼成环。
设总共有 \(m\) 棵树,那么设一个大小为 \(k\) 棵树的环,那么其出现的次数就是 \(n^{m-k}\)。
对于钦定某 \(k\) 棵树构成的环,方案数是 \((k-1)!\prod siz_k\),代表每棵树的根连向哪里的贡献。
这是一个背包,简单解决即可。
AGC028C Min Cost Cycle
先贪心地选出 \(a,b\) 最小的 \(n\) 个数,那么我们选 \(n\) 条边,使得每条边都只有一个点被选。
经过手玩盲猜只需要存在一个 \(a_i,b_i\) 都被选就存在一种回路方案。
或者是 \(a\) 全都被选了或者 \(b\) 全都被选了。然后你后面瞎几把搞就行了。
ARC121D 1 or 2
逆天孩子,只需要把一个数看成与 \(0\) 匹配即可,然后枚举 \(0\) 的个数,最后贪心匹配。
P4426 [HNOI/AHOI2018] 毒瘤
新科技广义串并联图。
根据经典结论,通过以下三个操作,最终得到的图的边数是 \(V=2k,E=3k\) 级别的。
三个操作是:消串联(选一个二度点合并其两端);消并联(删重边),去断路(删一度点)。
考虑在上述过程中维护答案。考虑维护 \(f_u,g_u\) 表示考虑 \(u\) 上挂的点,\(u\) 选/不选的方案数。
同时维护每条边三种情况 \((0,0),(0,1),(1,0)\) 的方案数。
最后统计答案的话考虑枚举每个点选不选再乘起来即可。
消串联的话,考虑枚举中间的点是 \(0/1\),然后贡献简单计算。
消并联可以用一个 map 维护是否有边,注意到重边的贡献是独立,直接相乘即可。
去断路的话,就是更新与其连接的那个点的 \(f,g\) 值。
具体实现可以类比拓扑排序。
AGC005E Sugigma: The Showdown
观察样例,A 可以一直躲避下去的方式是已知躲在某条边,使得其两端点在 B 树的距离 \(\ge 3\)。
那么我们可以找出这样所有的边,只要 A 能到达这样的边那么 A 就获胜了。
所以 B 是要在 A 前往这些边的过程中阻碍 A 到达。
那么,所以如果 B 要获胜,那么一定不能让 A 到达这些边的任何一个端点对吧,
所以 B 到这些边的每个端点的距离一定是小于 A 所到达的,对吧。
如果 B 一定赢,那么 A 的策略一定是躲到距离 B 最远的某个叶子处,所以找到这个点即可。
是不是说 B 到上述每个对 A 胜利的点距离都比 A 小就赢了呢?是的,并且我们还可以在路上阻断他。
条件是如果 \(dis_{A,u}>=dis_{B,u}\) 那么 \(A\) 一定不能到达这个点 \(u\)。这个条件经常被用到。
可以理解为 B 就是走了一条最快靠近 A 的路,反正 A 是不能回头因为会更亏的。
所以我们以 A 定根做一遍 dfs,只能走 B 不能更快到达的点,看能不能走到一条胜利边即可。
如果走不到,就计算能走的点距离 B 最远的点是哪个,A 就躲在这里。
P7897 [Ynoi2006] spxmcq
对于每个 \(x\) 我们都有一个树形 dp 就是 \(dp_{u}=a_u+x+\sum \max(0,f_v)\)。
也就是:如果当前子树为贡献正数,那么就可以向父亲贡献。
同时因为这题可以离线,所以这启示我们按照 \(x\) 从小到大排序加入。
那么我们可以维护当前已经向上贡献的边,因为 \(x\) 从小到大,那么一旦贡献以后就都会有贡献。
所以我们相当于维护若干连通块。那么我们需要当 \(x\) 增加时寻找贡献将变为正数的子树。
设该子树目前总共有 \(siz\) 个点贡献,原始 \(a_i\) 的和距离 \(0\) 是 \(d\),\(x\) 增加到 \(d/siz\) (上取整)时即为正。
所以我们考虑用一个堆维护当前最小 \(d/siz\),每次取出最小的并向上合并,并更新上面的。
合并的话考虑用并查集处理。然后修改的话是一个链加的形式。差分转化为求子树和即可。
离线+维护连通块。
P8277 [USACO22OPEN] Up Down Subsequence P
贪心地,对于 \(i\) 结尾的子序列,一定是保留最长的最好。证明比较难,纯靠感觉。
那么树状数组维护 dp。
P10060 [SNOI2024] 树 V 图
考虑找充要条件,那么就是取出所有两端颜色不同的边出来,设这条边为 \((u,v)\)。
设 \(d_u\) 表示其到其对应的关键点的距离,钦定 \(f(u)<f(v)\),那么 \(d_u-d_v\in [0,1]\)。
同时注意到每个颜色形成一个连通块,连通块之间又有一个树形结构关系。
那么考虑树形 dp,设 \(f_{u,k}\) 表示 \(u\) 这个连通块,其关键点到顶端距离为 \(k\) 方案数。
P10857 【MX-X2-T6】「Cfz Round 4」Ad-hoc Master
非常地 Ad-hoc 一个题。
首先考虑所有 \(u\),\(f_{u,k}\) 全部异或起来,那么这个值对应深度为 \(k\) 的所有点的异或和。
证明比较显然,当且仅当一个深度为 \(k\) 的点,距离其为 \(k\) 的点数为奇数。
那么我们可以找到根节点的编号,只需要找到一个匹配上就可以了。
那么考虑求根节点的值。我们可以求出除了根节点外所有点的异或和。
那么注意到,两个距离为奇数的点 \(u,v\),所有 \(f_{u,2k+1},f_{v,2k+1}\) 异或起来就是所有点的异或和。
如果 \(u,v\) 距离是偶数那么抵消异或和为 \(0\)。所以我们钦定 \(u\),枚举 \(v\),找一个不为 \(0\) 的即可。
如果全 \(0\) 那么就是所有异或为 \(0\)。最后异或除了根节点外所有点的异或和就是根节点权值。
P8314 [COCI2021-2022#4] Parkovi
显然二分+贪心。考虑二分 \(mid\)。
那么贪心地,从子树开始填关键点,能“咕”则“咕”即可,也就是把关键点放到深度最浅的位置。
对于一个点 \(u\),我们先递归其所有子树,并求出最深未覆盖的点深度 \(f\) 和最浅的关键点深度 \(g\)。
如果 \(g\) 可以覆盖 \(f\),那么把 \(f\) 清掉即可。
否则如果此时不放关键点的话,\(f\) 就覆盖不到了,我们就放,否则不放。嗯。
这种以子树形式划分子任务的贪心非常的典且非常的重要。
P6817 [PA2013] Filary
取 \(m=2\),答案下限是 \(n/2\)。那么我们随机一个位置的数 \(a_x\) 出来,每次选对的概率 \(>1/2\)。
考虑把 \(|a_i-a_x|\) 拿出来,质因数分解,我们选出现次数最多的质数作为 \(m\)。
但是可能答案是合数,那么我们要把两个质数合并,两个质数合并的条件是其出现的位置完全相同。
那么判断集合的相同我们考虑用 xor-哈希处理。
注意特判质数的幂次。
P9521 [JOISC2022] 京都观光
考虑从 \((i,x)\) 走到 \((j,y)\),若只有两种走法:先右再下/先下后右。
那么移项可得若 \(\frac{B_x-B_y}{x-y}\le \frac{A_i-A_j}{i-j}\),那么就先向下走,否则就先向右走,这个对应斜率。
但是如果中间走别的一条路呢?钦定原本是先往下走,现在中间多了一条 \(A_k\)。
那么就转化为与 \(\frac{A_k-A_j}{k-j}\) 和 \(\frac{B_x-B_y}{x-y}\) 比较。所以说,我们每次选择都需要选择斜率更小的。
所以我们贪心。但是遇到一个问题就是如果是比较向右和向下的两条边的话,我们看不到后面的情况。
根据经典套路,我们需要将序列划分为斜率不降的若干段。使得当前选择不会有后效性。
相当于维护两个下凸包。然后我们维护两个指针走即可。
如果有多组询问,取出询问情形的凸包,而不是走到终点的两个凸包。
相当于将整段路程分割为若干个从 \((i,x)\) 走到 \((j,y)\) 的比较。
P1792 [国家集训队] 种树
突然发现一个典题不会做。我们如果贪心就是取出前 \(k\) 大对吧。
考虑 \(k=2\),即已经选了一个数之 \(a_u\) 后,下一个要么选一个不相邻的,或者选 \(a_{u-1},a_{u+1}\) 删掉 \(a_u\)。
我们可以考虑将 \(a_{u-1},a_{u+1}\) 删掉,并把 \(a_u\) 置为未选,权值设为 \(a_{u-1}+a_{u+1}-a_u\)。
\(a_u\) 的选或不选,相当于对应 \(a_{u-1}+a_{u+1}\) 和选 \(a_u\) 其本身,同时这样还是满足相邻不能同时选的限制的。
根据贪心,我们每次要选择贡献最大的,那么我们维护一个堆即可。
删除操作考虑用一个环形链表处理。
AT_code_festival_2017_qualb_f Largest Smallest Cyclic Shift
太逆天一个题了。证明的话?
每次取出字典序最小的串和字典序最大的串合并,直到只有一个串存在。
AGC023D Go Home
考虑每个楼房的人是怎么投票的。比较明显的投家的方向是错的,可能会“反水”。
即,因为人数的差距,即使现在往家的方向走,最后还是要往反方向走,浪费更多时间。
考虑时光倒流,注意到最后一步一定是从 \(1\) 走到 \(n\),或者从 \(n\) 走到 \(1\)。
那么现在相当于只有 \(1,n\) 没有到,那么一定会先到 \(a\) 大的那一边,再走到另一边。
钦定 \(a_1>a_n\),那么既然一定先到 \(1\),所以 \(n\) 会反水,那么令 \(a_1\gets a_1+a_n\),并删掉 \(n\) 递归。
这是借时光倒流思想,递归,划分子任务。
AGC010E Rearranging
我们先有一个图论建模,将不互质的两个数连起来,代表这两个数相对位置不变,即被“卡住”。
假设我们钦定了这些数的先后关系,考虑后手的策略,类似拓扑排序,贪心每次取出最大的能选的数。
所以现在相当于给边定向。
因为目前所有数都可以被第一个选,我们要让大的数被卡住,所以大的数要有小的数连入。
考虑一个连通块,我们第一个选的肯定是其中最小的数,来卡住其他大的数对吧。
接下来,最小的数肯定希望下一个接的还是小的数,所以找出边最小的数 dfs。
所以一直 dfs 下去即可。哎呀我也不会证。
考虑这就是一个搜索树,然后不同的子树独立,要想他们不独立呢,就要能走即走,也就是深搜。
CF1458D Flip and Reverse
神仙题,考虑将 \(0\) 看做 \(-1\),\(1\) 看做是 \(1\),我们操作 \([l,r]\) 的话,相当于反转 \(sum_{l}\sim sum_{r-1}\) 的数组。
所以相当于自由调换 \(sum\) 的位置,但是有一些不变量,比方说 \((sum_{l-1},sum_l)\) 这两个值一定相邻。
那么转化为图论模型,我们只需要确保 \((sum_{i},sum_{i-1})\) 这种边存在即可。
现在相当于一个欧拉路径。字典序最小可以转化为 \(sum\) 数组的字典序最小。那么贪心即可。
CF1610G AmShZ Wins a Bet
注意到,要删括号必须将其中间全部删完,因为要不然第一个右括号删完会左移。
所以我们每次删除都是必须删掉一个合法括号子串。
根据最优化字典序的常见方法我们从后往前 dp,最优化后缀,即设 \(dp_{i}\) 表示 \(i\) 后缀的字典序最小串。
那么 \(dp_i=\min(s_i+dp_{i+1},dp_{nxt_i+1})\),其中 \(nxt_i\) 表示极短的以 \(i\) 开头的括号匹配串的结束位置。
那么这个 dp 牵扯到字符串的比较。考虑用到可持久化数据结构,然而这么做是双 \(\log\) 的。
考虑倍增跳,相当于转移树取出来树上倍增,维护哈希值即可。
细节地,倍增维护的是第 \(1+2^i\) 的字符的位置,以及 \(pos_i\) 维护 \(dp_i\) 答案串的开头是哪里。
P6346 [CCO2017] 专业网络
先转化一下题意,就是给 \(a\) 分配一个 \(1\sim n\) 的次序,然后若 \(a_i> i-1\),那么就可以获得 \(-b_i\) 的收益。
其中,分配第 \(i\) 个相当于第 \(i\) 个认识,而此时已经认识了 \(i-1\) 个人。
相当于有若干个任务,任务的有效期是 \([1,a_i+1]\),收益是 \(-b_i\),一个时间只做一个任务,问最大收益。
贪心地,任务越后做越优。所以我们时间倒着做,在第 \(i\) 个时刻做此时能做且未做的最大收益的任务。
用堆维护即可。
CF1411F The Thorny Path
首先相当于优化 \(k^{n/k}\) 的值,根据小学知识得到 \(k=e\) 最大。而 \(k\) 要是整数,故分成大小为 \(3\) 的环最优。
但是可能 \(3\not|n\),如果 \(n\bmod 3=1\),那么相当于多一个 \(4\) 或两个 \(2\);如果 \(n\bmod 3=2\) 就多一个 \(2\)。
注意到,对于一个大环大小为 \(m\),操作一次可以使得其变成任意大小的两个环。反之也可以拼回去。
所以我们贪心地先对大环取出若干个大小为 \(3\) 的环,每次代价为 \(1\);
然后剩下 \(1,2\) 的环匹配,每次代价为 \(1\);最后 \(1,2\) 还有多的自己匹配,代价为 \(2\)。
特判 \(n\bmod 3=1\) 的情况,因为 \(4\) 和两个 \(2\) 等价,牵扯到最后取哪个的分讨。
即:如果有 \(\ge 4\) 且余 \(1\) 的且 余 \(2\) 的没有多的,就考虑用这个 \(4\)。
否则考虑用已有的两个余 \(2\) 的;若不够就用两个 \(1\) 补;若没有余 \(2\) 的就考虑 \(1+3\) 或者四个 \(1\)。
CF725F Family Photos
很牛的贪心。值得记录。
我们想如果一叠照片只有一张的话如何选择。我们不妨想第一张取的是哪个。
如果只有两张,我们第一张取 \(i\) 而不取 \(j\) 的条件是:\(a_i-b_j\ge a_j-b_i\),移项得 \(a_i+b_i\ge a_j+b_j\)。
拓展到多张每叠只有一张的情况,也就是按照 \(a_i+b_i\) 从大到小排序轮流取。也就是通过邻项交换证明。
那么每叠有两张呢?如果 \(a_{i,1}+b_{i,1}> a_{i,2}+b_{i,2}\),那么相当于已经排好序了,那么两叠等于独立。
如果 \(a_{i,1}+b_{i,1}\le a_{i,2}+b_{i,2}\),也就是 \((a_{i,1}-b_{i,2})+(b_{i,1}-a_{i,2})\le 0\)。
若 \(a_{i,1}-b_{i,2}\le 0,b_{i,1}-a_{i,2}\le 0\),那么 AB 肯定都不会选,因为选了肯定更劣。
若 \(a_{i,1}-b_{i,2}\le 0,b_{i,1}-a_{i,2}>0\),那么 A 肯定不会选,但是 B 会选,所以直接算上贡献。
\(a_{i,1}-b_{i,2}> 0,b_{i,1}-a_{i,2}\le 0\) 同理,A 一定会选,B 不会选。
CF1844F2 Min Cost Permutation (Hard Version)
首先先观察一些性质。钦定 \(x\le y\),那么 \(|x-1-c|+|y+1+c|\ge |x-c|+|y-c|\)。
也就是说,当所有数的和一定的情况下,这些数越集中答案越优。
注意到当 \(c=0\) 的情况下,数全部递增或递减都是最优,为了字典序最小我们取递增的序列为答案。
我们猜测,当 \(c\ge 0\) 的情况下,数全部递增是最优的。
证明的话,考虑邻项交换,设 \(A,B,C,D\),交换 \(B,C\) 的话使得 \(B-C\) 变为 \(C-B\) 一定变得不集中。
并且,数全部递增字典序也是最小的,那么我们就解决了 \(c\ge 0\) 的情况。
考虑 \(c<0\),同理数全部递减答案是最优,但是字典序不一定最小。将 \(a\) 降序排列。
逐位确定,设该位确定了 \(b_i=a_j\),那么未确定的数按照降序填入后面后,答案不会更劣就可以填。
然而这样做是 \(O(n^2)\) 的,考虑优化找 \(b_i\) 的最小值这个过程。
找条件,设 \(b_i\) 填 \(a_j\) 这个数,满足 \(a_j-b_{i-1}\ge c\) 且 \(a_{j+1}-a_{j-1}\ge c\)。
那么我们只需要支持查询最小的 \(a_j\) 满足 \(\ge b_{i-1}+c\) 且 \(a_{j+1}-a_{j-1}\ge c\) 即可。
直接用 set 维护,再用链表维护 \(a\) 的前驱后驱。