ABC 443 DEFG
D - Pawn Line
赛时是猜出来的,但感觉这道题还需要仔细回味一下,如何证明很重要。
这里直接搬其他博主的思路讲解了:zhihu
E - Climbing Silver
官解用的是 dp,这里给一个容易理解还好写的做法:直接 bfs + 树状数组模拟整个过程,对每一列倒着维护墙数量的前缀和,在 bfs 过程中动态着删可以删除的墙,复杂度 \(O(n^{2}\log n)\)。具体实现见代码。
F - Non-Increasing Number
考虑 \(dp\)。
状态定义:\(dp_{r,c}\):在 \(\% n\) 意义下,得到余数为 \(r\),且当前末尾数字是 \(c\),数字的最小位数。
初始时没有任何数字, \(dp_{0,0} = 0\)。
状态转移:
\[dp_{(x*10+c')\% n,c'} \leftarrow dp_{x,c} + 1,c' \in [\max(1,c), 9]
\]
由转移式可知,这类似于 \(bfs\),因此我们可以直接用队列模拟整个 dp 转移过程,每次从队首弹出的状态值都是最小的(也就是位数最少)。发现当前状态的余数 \(r=0\) 时(\(\% n = 0\),说明是 \(n\) 的倍数),说明找到了最优解。
剩下的就是还原方案,记录整个 bfs 过程中的 dp 转移路径并回溯即可。若无解,则会搜索到所有可能的状态,而总状态数是 \(O(10*n)\) 的,仍然可以直接模拟。具体实现见代码。
summary: 像这种需要找到某个数的倍数作为答案的数位题,一般考虑用余数作为 dp 转移的状态。
G - Another Mod of Linear Problem
需要用到类欧几里得算法,对本蒟蒻来说属实超纲了qwq。。。
那么剩下的问题就是如何在 \(n\) 很大时快速求:
\[\sum_{i=0}^{n} \lfloor \frac{ai+b}{c} \rfloor
\]
类欧几里得算法:blog
模板:
typedef __int128 LL;
LL calc(LL a, LL b, LL c, LL n) {
if(n < 0) return 0;
if(a == 0) return (b / c) * (n + 1);
LL n2 = n * (n + 1) / 2;
if (a >= c || b >= c)
return calc(a % c, b % c, c, n) + (a / c) * n2 + (b / c) * (n + 1);
LL m = (a * n + b) / c;
if (m == 0) return 0;
return m * n - calc(c, c - b - 1, a, m - 1);
}
ll Euclid_f(int a, int b, int c, int n){ // 为了避免 a, b 存在负数的情况,需要再套一层
int ar = (a % c + c) % c;
int aq = (a - ar) / c;
int br = (b % c + c) % c;
int bq = (b - br) / m;
return 1ll * aq * (1ll * n * (n + 1) / 2) + 1ll * bq * (n + 1) + calc(ar, br, c, n);
}




浙公网安备 33010602011771号