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|)\)

posted @ 2020-11-03 23:44  AE酱  阅读(193)  评论(0编辑  收藏  举报