扩大
缩小

AtCoder 竞赛典型 90 题,解题报告

提示:每题括号内的数字大致表示难度。

001 - Yokan Party(★4)

题意

有一个长度为 $L$ 的纸条。在 $N$ 个位置 $a_1,a_2,...,a_n$ 找 $K$ 个分割点,最大化最短段的长度。

$1 \le K \le N \le 10^5$,$0<a_1<a_2<...<a_n<L \le 10^9$。

解析

二分最短段的长度 $l$,贪心来强制每段 $\ge l$,检验是否能凑出 $\ge k+1$ 段。

代码:https://atcoder.jp/contests/typical90/submissions/35153678

002 - Encyclopedia of Parentheses(★3)

题意

按照字典序打印所有长度为 $n$ 的合法括号序列。

$1 \le n \le 20$。

解析

$n$ 是奇数就不输出,否则可以 DFS 解决。

代码:https://atcoder.jp/contests/typical90/submissions/35154547

003 - Longest Circular Road(★4)

题意

给定一棵 $n$ 个节点的树,加一条边使得构成的环包含点数最多。

$1 \le n \le 10^5$。

解析

这个问题等价于求树的直径。(即距离最远的两点的路径经过的点数)

两种解法:

  1. 利用贪心的想法。先找到距离节点 $1$ 最远的点 $p$,再找到距离 $p$ 最远的点。执行两次 DFS 即可。
  2. 假设点 $1$ 为根,对于每个节点 $x$,找到其子树中最长的两条能接上 $x$ 的链(不能有交点),把 $x$ 接上去计算答案。

代码:

  • 做法一:https://atcoder.jp/contests/typical90/submissions/35394771
  • 做法二:https://atcoder.jp/contests/typical90/submissions/35394830(这个做法本来是 $\mathcal{O}(n)$ 的,但是代码偷懒用了排序)

004 - Cross Sum(★2)

题意

给定一个 $H \times W$ 的矩阵,对于每个位置 $(i,j)$ 求出所有在第 $i$ 行第 $j$ 列的元素和。 

$1 \le H,W \le 2000$,矩阵元素是 $[1,99]$ 间的整数。

解析

建立分别记录每行、每列元素和的数组,在输入的时候,就将每个数存入对应的位置,最后对于每个位置就可以 $\mathcal{O}(1)$ 查询。

代码:https://atcoder.jp/contests/typical90/submissions/35395190

005 - Restricted Digits(★7)

题意

(题目已运到 YZOJ 5970)

有多少个 $N$ 位十进制数,满足每位数字都在集合 $S$ 中,且它是 $B$ 的倍数?答案对 $10^9+7$ 取模。

任务一:解决 $N \le 10000, B \le 50$。

任务二:解决 $N \le 10^{18}, B \le 50$。

任务三:解决 $N \le 10^{18}, B \le 1000$。

集合 $S$ 内只有 $1 \sim 9$ 间的整数。

解析

对于任务一,我们设 $dp_{i,j}$ 表示目前已经确定 $i$ 位,当前数字除以 $B$ 余 $j$。直接转移是 $\mathcal{O}(NB^2)$ 的。

对于任务二,我们发现 $dp_{i,j}$ 只与 $dp_{i-1,k}$ 有关,而且第二维大小不超过 $50$,可以考虑矩阵加速。时间复杂度 $\mathcal{O}(B^3 \log N)$。

任务三尚待补充……

006 - Smallest Subsequence(★5)

题意

有一个长度为 $N$ 的小写字符串 $S$,请从中找到长度为 $K$ 且字典序最小的子序列 $T$。

$1 \le K \le N \le 10^5$。

解析

根据字典序的策略,只要能保证能凑满 $K$ 个字母,那尽可能要保证越靠前的字母,它越小。

所以假设当前我们将 $T_p$ 定为了 $S_q$,那么相当于剩余的 $N-q$ 字母,我们要挑 $K-p$ 个出来。

那么接下来要填的那个字母可能分布在哪里?在区间 $[N-q, \ N-q-(K-p-1)]$。这是因为我们要保证还没被挑的 $K-p-1$ 个字母有位置。

剩下的任务,就是在区间 $[N-q, \ N-q-(K-p-1)]$ 内找到最小的字母,同时保证它下标尽量小(为了让后面的挑选范围尽量大)。

这个任务可以使用多标记的线段树。标记存两个东西:区间最小的字母,以及它所在的原串下标(且是尽可能小的)。

细节就不多说了,可以看这份代码:https://atcoder.jp/contests/typical90/submissions/36932587

007 - CP Classes(★3)

题意

数轴上有 $n$ 个点 $a_1,a_2,...,a_n$,有 $q$ 个询问,每次输入一个位置 $x$,求出距 $x$ 最近的点到它的距离。

$N,Q \le 3 \times 10^5$,$0 \le a_i,x \le 10^9$。

解析

可以二分,也可以排序 + 双指针。注意边界情况。

代码:https://atcoder.jp/contests/typical90/submissions/36932727

008 - AtCounter(★4)

题意

给一个长为 $N$ 的小写字母串。求有多少个不同的子序列,等于 "atcoder"。

$N \le 10^5$。

解析

观察到 atcoder 这七个字母互不相同,可以设 $dp_{i,0/1/2/3/4/5/6}$ 代表枚举到第 $i$ 位且分别以 $a,t,c,o,d,e,r$ 结尾的字符串个数。

转移方程:$dp_{i,j}=\sum dp_{i-1,j-[t_j=s_i]}$。时间复杂度 $\mathcal{O}(n)$。

代码:https://atcoder.jp/contests/typical90/submissions/36932826

011 - Gravy Jobs(★6)

题意

有 $n$ 项工作。第 $i$ 项工作需要在第 $d_i$ 天及更早结束,一次耗时 $c_i$ 天(不能间断)。完成后可以获得报酬 $s_i$。

如果一个人一天只能做一项工作,请求出最大报酬。

$1 \le n,d_i,c_i \le 5000$,$1 \le s_i \le 10^9$。

解析

根据贪心策略,越早截止的工作,应尽早开始完成。所以我们先按照 $d_i$ 升序排序。

如果没有截止日期的限制,这就是一个背包问题(截止日期为容量)。

现在加上这个限制,由于工作已经被排序,我们可以认为每次新加入一个工作,背包就会被扩容。

然后就和普通的背包没什么区别了。

代码:https://atcoder.jp/contests/typical90/submissions/36933185

015 - Don't be too close(★6)

题意

给定 $n$。你将得到一个序列 $1,2,...,n$。对于每个 $x=1,2,3,...,n$,求出有多少个子序列满足序列内的元素两两相减绝对值均 $\ge x$。

答案对 $10^9+7$ 取模,$1 \le n \le 10^5$。

解析

如果直接动态规划,时间复杂度是 $\mathcal{O}(n^2)$ 的,过不了。那么考虑问题的组合数学意义!

对于每个 $x \ (x \ge 1)$:

  • 我们枚举 $t=1 \sim \lfloor\frac{n}{x}\rfloor$ 代表子序列包含的元素个数。
  • 容易发现会有 $(x-1)(t-1)$ 个空隙是不能填数字的,我们将其抽走,那么序列只剩 $n-(x-1)(t-1)$ 个位置,供这 $t$ 个数选取位置。
  • 所以对于每个 $x$,答案即为 $\sum\limits_{i=1}^{\lfloor\frac{n}{x}\rfloor}\binom{n-(x-1)(i-1)}{i}$。

由于 $\sum\limits_{i=1}^{+∞}\frac{n}{i}= \ln n$,因此预处理组合数的情况下,时间复杂度可以做到 $\mathcal{O}(n \ln n)$。

代码:https://atcoder.jp/contests/typical90/submissions/37983375

016 - Minimum Coins(★3)

题意

有三种面值的硬币 $A,B,C$。问最少多少个硬币可以支付恰好 $N$ 元。

$1 \le A,B,C,N \le 10^9$,答案 $\le 9999$。

解析

直接枚举 $A,B$,可以间接求出 $C$,然后比较答案。

代码:https://atcoder.jp/contests/typical90/submissions/38166776

019 - Pick Two(★6)

题意

有一个长为 $2n$ 的序列 $a_1,a_2,...,a_{2n}$。每次选中当前相邻的两个数 $a_i,a_{i+1}$,删除它们,代价是 $|a_i-a_{i+1}|$。

每次把两个数删除后,剩下的序列会拼在一起。问删光序列的最小代价和。

$n \le 200$,$a_i \le 10^6$。

解析

每次都是删除当前序列的两个相邻位置的数,那么如果原序列两个数正在被删除,就代表它们之间的数已经删光了。

所以可以上区间 DP。$dp_{i,j}$ 表示将序列子区间 $[i,j]$ 删空的最小代价。

$dp_{i,j}$ ($j-i+1$ 为偶数且大于等于 $4$)有两种构成方式:

  • 将 $[i,j]$ 拆成两个偶数段,相加取最小值;
  • 将 $[i+1,j-1]$ 拆成两个偶数段,相加,并加上 $|a_i-a_j|$ 取最小值。

如上转移即可。时间复杂度 $\mathcal{O}(n^3)$。

代码:https://atcoder.jp/contests/typical90/submissions/37984053

020 - Log Inequality(★3)

题意

比较 $\log_2 a$ 与 $b \log_2 c$ 的大小。

$1 \le a \le 9 \times 10^{18}$,$1 \le b \le 17$,$1 \le c \le 13$。

解析

两边变指数,分别变为 $a$ 与 $c^b$ 比大小。

代码:https://atcoder.jp/contests/typical90/submissions/38166870

025 - Digit Product Equation(★7)

题意

定义 $f(x)$ 表示 $x$ 十进制下每位数字的乘积(不含前导 $0$)。

求 $1 \sim N$ 有多少数 $x$ 满足 $x-f(x)=B$。

$1 \le N,B \le 10^{11}$。

解析

先枚举当前有几个数位。对于每个数位 DFS 一次。

看到这有人会问:这范围那么大,DFS 不会搜爆掉吗?OK,我们来分析一下怎么搜。

没有剪枝的时候,每个数位都有 $10$ 种可能,但实际上这会产生很大的效率浪费。

比如 $123,132,213,231,312,321$ 这六个数,它们的 $f(x)$ 均为 $6$。

然后 $B$ 是固定的,可以知道此时 $B+f(x)$ 已经被确定下来了。所以这 $6$ 个数最多只会有一个是符合条件的。

这个事情告诉我们,我们在搜索数字的时候,可以强制后面的数位大于等于前面的数位

之后,我们需要判断,将当前的 $x$ 数位改变一些顺序,能不能使得它等于定值 $f(x)+B$。

此时不需要大费周章去全排列枚举,只需要将 $x$ 和 $f(x)+B$ 两数的数位分别升序排列,比较这两个序列相同情况就可以了。

注意判断数字是否在上界 $N$ 以内。

这个做法时间复杂度并不好计算,但是可以写个程序测试一下,可以发现这种方式生成的 $x$ 不到 $5 \times 10^5$ 个。

代码:https://atcoder.jp/contests/typical90/submissions/37100318

029 - Long Bricks(★5)

题意

一条直线按顺序有 $W$ 个位置,接下来天上会掉下来 $n$ 个横条形的俄罗斯方块。

第 $i$ 个方块占据了位置 $[L_i,R_i]$。根据俄罗斯方块规则,它会一直下落直到底面的某处碰到了地面或别的方块。

如果每个俄罗斯方块高为 $1$,请求出每个方块停止下落的时候,它所在的高度。

$1 \le L_i \le R_i \le W \le 5 \times 10^5$,$1 \le N \le 2.5 \times 10^5$。

解析

本题涉及到区间求 $\max$,区间修改,是个经典的线段树维护懒标记的题目。

由于这题比较模板,就不多说了,具体细节可以看代码:https://atcoder.jp/contests/typical90/submissions/38139303

030 - K Factors(★5)

题意

给定 $N,K$,$1 \sim N$ 有多少个正整数,它至少有 $K$ 个素因数?

$2 \le N \le 10^7$,$K \le 8$。

解析

两个做法:

  • 埃氏筛法,每个质数向后跳倍数,时间复杂度 $\mathcal{O}(n \log \log n)$。
  • 线性筛。记 $fac(i)$ 表示数字 $i$ 的最大素因子,设数字 $x$ 的质因子数为 $f(x)$,那么可以 $\mathcal{O}(n)$ 转移,如下:

$$f(x)=f(\frac{x}{fac(x)})+[fac(\frac{x}{fac(x)}) \neq fac(x)]$$

代码(第一种做法):https://atcoder.jp/contests/typical90/submissions/38139369

039 - Tree Distance(★5)

题意

给定一棵 $n$ 个节点的树,树上的边边权均为 $1$,求树上两两节点距离之和。

$2 \le n \le 10^5$。

解析

这是一个经典的树上换根 DP 题。下面简述下解法:

  • 第一步,用一次 DFS 遍历算出以 $1$ 号节点为根,到其它每个点的距离 $d(i)$,以及每个节点以自己为根的子树大小 $size(i)$。
  • 设此时的距离和为 $S$。
  • 第二步,换根。同样按照 DFS 遍历顺序,如果以前根为 $x$,此时根从 $x$ 换成 $y$。
  • 对于$S$ 此时将变成 $S-size(y)+n-size(y)$。因为就 $y$ 及其子树而言,它到新根的距离都减少了 $1$;就子树 $y$ 以外的节点而言,它到新根的距离都增加了 $1$。
  • 将每个点为根时的 $S$ 相加,就是答案。

注意 DFS 回溯时要还原信息。代码:https://atcoder.jp/contests/typical90/submissions/38139648

066 - Various Arrays(★5)

题意

见 YZOJ 5973。

有一个长度为 $n$ 的序列 $a_1,a_2,...,a_n$。其中 $a_i$ 将从 $[L_i,R_i]$ 区间中随机抽取一个整数作为它的值。

请求出整个序列的逆序对的期望数

原题范围:$1 \le n \le 100$,$1 \le L_i \le R_i \le 100$。

加强版范围:$1 \le n \le 5000$,$R_i$ 在保证存在 double 内精度正常的情况下无特殊限制。

解析

由期望的线性性,整个逆序对的期望数,等于两两位置比较,产生的逆序对的期望数。

而所谓两两位置比较的逆序对,就是位置靠前的数大于位置靠后的数的概率

所以先两两枚举下标 $i,j \ (i \le j)$,接着 $a_i,a_j$ 也逐个枚举,判断它们的大小,累加后除以总数即得到概率。

时间复杂度 $\mathcal{O}(n^4)$ 级别($n$ 与 $a_i$ 同阶),通过前缀和优化可以达到 $\mathcal{O}(n^3)$。

对于加强版,我们就不能逐个枚举 $a_i,a_j$ 的值了,而是直接根据这两组 $[L_i,R_i], \ \ [L_j,R_j]$ 比较 $a_i>a_j$ 的概率。

此时要分六类讨论:

  • $R_i < L_j$,易知概率为 $0$;
  • $L_i > R_j$,易知概率为 $1$;
  • $L_i \le L_j \le R_i \le R_j$,分开考虑区间 $[L_i,R_i]$ 与 $[L_j,R_j]$ 的相交片段的概率,和分离片段的概率。
  • $L_j \le L_i \le R_j \le R_i$,同上一种情况。
  • $L_j \le L_i \le R_i \le R_j$($i$ 是 $j$ 的子区间);
  • $L_i \le L_j \le R_j \le R_i$($j$ 是 $i$ 的子区间)。

此时时间复杂度 $\mathcal{O}(n^2)$。代码:https://atcoder.jp/contests/typical90/submissions/38141000

posted @ 2022-10-04 18:47  HoshizoraZ  阅读(492)  评论(0编辑  收藏  举报