Codeforces 日常训练1
把近期做的CF题总结一下,会比较简短。
CF618D Hamiltonian Spanning Tree
给定一张 \(n(n\leq 200000)\) 个点的无向完全图,每条边的边权均为 \(y\) 。再给出这张图的一棵生成树,每条树边边权都为 \(x\),求该图的最短哈密顿路径。
考虑 \(x\) 和 \(y\) 的关系。如果 \(x=y\),答案为 \((n-1)x\) 。如果 \(x>y\),则要尽可能多地选不在树上的边,那么如果存在一个点的度数为 \(n-1\),则说明至少要走一条树边,答案为 \(y(n-2)+x\),否则可以全不走树边,答案为 \((n-1)y\)。如果 \(x<y\),说明要尽可能多地走树边,则转化为树的最小路径点覆盖问题,树上dp即可。
CF1436D Bandit in a City
给定以 \(1\) 为根的 \(n(n\leq 2\times 10^5)\) 个节点的一棵树,每个节点上有 \(a_i\) 个人,每个人可以选择往任意子节点走,直到走到叶子节点为止,问最后人最多的叶子节点最少有多少人。
不难发现答案具有单调性。我们可以去二分人最多的叶子节点的人数,然后每次通过一次DFS来判是否合法。
CF1433G Reducing Delivery Cost
给定一个 \(n\) 个点 \(m\) 条边的无向带权图,你能使一条边的边权权变为 \(0\),求 \(k\) 组点对间最短路之和最小值。\((n,m,k\leq 1000)\)。
假设我们将 \((x,y)\) 这条边的边权置为 \(0\),那么从 \(u\) 到 \(v\) 的所有最短路径分为两类:经过 \((x,y)\) 的和不经过 \((x,y)\) 的,可以由此求得新的最短路。因为点数和边数只有 \(1000\),我们可以从每个点出发跑一次 dijkstra 求得全源最短路,然后枚举置零的边,再求 \(k\) 组点对此时的最短路之和。
CF1433F Zero Remainder Sum
给定 \(n\times m\) 的矩阵 \(A\),和一个整数 \(k\),要求每行只能选取不超过一半的元素,且总的选择元素的和要是 \(k\) 的倍数,求最大值。\((n,m,k\leq 70)\)
根据模 \(k\) 后的值,先每行分别dp一次,求得该行各模数下能选的最大值,然后对所有行dp一次,求得最终答案。
CF1428E Carrots for Rabbits
有 \(n\) 个数 \(a_1,a_2,\cdots,a_n\),你可以把一个数进行分割。现在要把这些数恰好分成 \(k\) 份,要求最小化所有数的平方和。\((1\leq n\leq k\leq 10^5,1\leq a_i\leq 10^6)\)。
贪心。如果把一个数 \(x\) 分成 \(k\) 份,最优的分法肯定是分成 \(x\mod k\) 个 \(\lfloor\frac{x}{k}\rfloor+1\) 和 \(k-(x\mod k)\) 个 \(\lfloor\frac{x}{k}\rfloor\)。令 \(f(x,k)\) 表示把 \(x\) 分成 \(k\) 份后最小的平方和,用一个小根堆维护 \(f(x,k+1)-f(x,k)\) 这一差值,每次优先取差值最小的累加进答案。
CF1426F Number of Subsequences
给定一个长为 \(n\) 的含有abc?
的字符串,?
可能是abc
中的任意一个,求所有可能的无?
字符串中,子序列abc
出现的次数。\((n\leq 2\times 10^5)\)
依次考虑每一个为 ?
或者 b
的字符,钦定它为 abc
的中心,我们分别求出它左边各位置上所有为 a
的方案数,和右边各位置上所有为 b
的方案数,相乘再分别累加即为答案。假设在左边存在 \(p\) 个 a
和 \(n\) 个 ?
,那么左边的方案数为 \(\sum_{i=0}^n(p+i)2^{n-i}\binom{n}{i}\)。令 \(f(n,p)=\sum_{i=0}^n(p+i)2^{n-i}\binom{n}{i}\),\(g(n)=\sum_{i=0}^{n} 2^{n-i}\binom{n}{i}\),\(h(n)=\sum_{i=0}^{n} i2^{n-i}\binom{n}{i}\),则 \(f(n,p)=p\cdot g(n)+h(n)\)。而 \(g(n)=3^n,h(n)=3h(n-1)+3^{n-1}\)。右边同理,时间复杂度 \(O(n)\)。
CF1443F Identify the Operations
给一个 \(1\sim n\) 的排列 \(\{a_n\}\),和选其中 \(k\) 个数的一个排列 \(\{b_k\}\),初始时序列 \(c\) 为空,第 \(i\) 次操作可以从 \(a\) 中删除一个数 \(a_p\),若 \(a_{p-1}=b_i\),则把 \(p-1\) 加入 \(c\),若 \(a_{p+1}=b_i\),则把 \(p+1\) 加入 \(c\),否则不合法。删除 \(a_p\) 后把后面的数全部前移一位。求 \(c\) 的方案数模 \(998244353\)。 \((1\leq k\leq n\leq 200000)\)。
还没构造出的 \(\{b_n\}\) 中的数一定是不能删除的,并且注意到假设我们要取 \(a_p=b_i\) 这个数,那么无论是删除 \(a_{p-1}\) 还是 \(a_{p+1}\),都对之后选的数的下标没有影响,即对 \(c\) 没有影响。我们只需要每次判断要选的数左右两边是否能被删,分别把答案乘上 \(0,1,2\) 即可,可以用数组模拟链表维护。
CF1445D Divide and Sum
给出 \(2n\) 个数,你要把它任意分成长均为 \(n\) 的两个序列 \(p\) 和 \(q\),要求 \(p\) 非减,\(q\) 非增,令 \(f(p,q)=\sum_{i=1}^n|p_i-q_i|\)。对于所有的 \(p,q\),求 \(f(p,q)\) 之和。
注意到绝对值其实是假的,无论怎么分,\(f(p,q)\) 始终等于 \(n\) 个最大的数之和减去 \(n\) 个最小的数之和,那么最终答案只要乘上 \(\binom{2n}{n}\) 即可。
CF1231E Middle-Out
给两个长为 \(n\) 的字符串 \(S,T\)。每次操作可以将 \(S\) 中第 \(i\) 个字符移到开头或结尾。若想要使得 \(S=T\),求最小操作次数。\((1\leq n\leq 100)\)。
显然答案为 \(n\) 减去 \(S\) 和 \(T\) 的某一子串的最长公共子序列的最大值。那么可以枚举 \(T\) 的子串的开头位置,然后去和 \(S\) 匹配,使用子序列自动机维护,时间复杂度为 \(O(|\Sigma|\cdot|S|+|S|\cdot|T|)\)。