Atcoder ABC406 题解

咕了很久的 ABC 题解,又回来了。

ABC406

A

少写一点字的做法是,将 \(a\)\(b\) 分转化成 \(60a+b\) 分,比较提交时间和 ddl 的大小即可。

submission.

B

按照题述,每次乘上一个乘数,判是否大于等于 \(10^k\)。判断的时候,为了不越界,可以使用 __int128

submission.

C

很难,大于 D,大于 F,和 E 不好说。

计数,一定要抓住对象的一些特征。这道题,我们可以对两个极值进行计数。
我们的方法是,对于每个极大值 \(a_i\),找出极小值为 \(a_j\),满足 \(a_i > a_{i+1} > \dots > a_j\)。然后,再暴力向左找出最近的 \(l\),满足 \(a_l < a_{l+1} < \dots < a_i\),向右同理找出 \(r\)。答案就是 \(\sum (i-l)(r-j)\)

看似复杂度很不正确。我们尝试分析。

对于每一个 \(i\),向右找出 \(j\) 的过程,有 \(a_i > a_{i+1} > \dots > a_j\)。这样,我们可以保证,对于每个 \(k \text{ satisfying } i < k < j\),在这个过程中(\(i\)\(1\)\(n\),寻找 \(j\))只会被枚举 \(1\),因为这样的 \(k\) 没法找出第二个 \(i\),让它能枚举到 \(k\)
也就是,找 \(j\) 的过程,均摊时间复杂度是 \(O(n)\) 的。

同理,找 \(l,r\) 的过程,也是均摊 \(O(n)\) 的。
故总复杂度 \(O(n)\)

submission.

D

每次要求删除一整行或一整列的垃圾。显然,每个垃圾只会被删掉一次。
又显然,每行(列)垃圾也只会被删掉一次。
于是我们开两个 vector 数组,分别记录该行(列)的所有垃圾的列(行)下标。每次暴力删掉垃圾即可,用 set 记录垃圾有没有删过。

时间复杂度的来源是暴力删除,以及判断垃圾是否删过。这里,实际上来源于不同行(列)的垃圾总数,乘上单次删除(判断)的时间复杂度。
注意,要用两个数组记录某行或某列是否被删过,防止多次询问一个有 \(O(n)\) 个垃圾的行(列),导致时间复杂度错误。

总时间复杂度 \(O(n \log n)\)

submission.

E

除了数位 DP,还能是什么呢?

\(f_{i, j}\) 表示小于 \(2^i\) 的数(即有 \(i\) 位)中,popcount 是 \(j\) 的数之和(即,\(i\) 位填 \(j\)\(1\))。
将小于 \(2^i\) 的数分为两类:首位为 \(1\) 的,和首位为 \(0\) 的。

对于首位为 \(1\) 的,我们拆成 \(2^{i-1}\) 和剩余 \(i-1\) 位,这两部分。
接下来,需要求解剩下 \(i-1\) 位,因为首位填过 \(1\) 了,故接下来 \(i-1\) 位只需填 \(j-1\)\(1\)。显然,方案数是 \(\binom{i-1}{j-1}\),而这部分的和是 \(f_{i-1, j-1}\)

对于首位为 \(0\) 的,我们直接有和为 \(f_{i-1, j}\)

故:\(f_{i, j} = f_{i-1, j} + f_{i-1, j-1} + 2^{i-1} \times \binom{i-1}{j-1}\)

统计答案时,将 \(n\) 拆成 \(\sum 2^k\),同样的思路拆贡献。
对于小于 \(n\) 的数,一定会在他和 \(n\) 的最长公共前缀处统计到答案。以此计算即可。

时间复杂度 \(O(\log^2 V + T\log V)\),其中 \(V\) 为值域。

submission.

F

史上最奶龙的 F 题。

每次删边,一个部分一定是这条边连接的深度较大的点的子树(以 \(1\) 为根意义下的)。另一部分自然是全局和减去这个子树和。

用树状数组维护 DFS 序,轻松做到 \((n \log n + q\log n)\)

submission.

G

不会。

posted @ 2025-05-17 21:22  Water_M  阅读(202)  评论(0)    收藏  举报