CF 846 F. (*2300)
直接枚举选择情况显然 $O(n^3)$,考虑使用一些数学和预处理。
注意到有取最大和最小,因此考虑排序。排序后只需考虑区间,降为 $O(n^2)$。
对数字 a[i]
,其因数的数量较少,设为 $k$。对每个因数维护 a[i]
之前数字中不互质的数字数量,及这些数字编号之和,即可通过容斥计算出和 a[i]
不互质的数字数量和编号和,进而计算出答案。
这题我没能独立想出来,第一次见这种容斥的用法!我当时还以为可以用某种具有 min/max 性质的东西来维护,但又确实和线段树不太一样……
绷语言
1 | factorList : Int -> [[Int]] |
有些缺点暴露出来:
- 整体自更新机制
rec
暴露了大量无用变量 - 没有
for
循环导致只能使用nope
来跳出循环 - 无法实现
foreach
以修改数组
我们来做点语法改进!
语法改进
首先注意到 rec
和尾递归函数等价,这可以解决暴露无用变量的问题。原先写阶乘函数是:
1 | let n = input |
使用尾递归函数则可以写成:
1 | let n = input |
但这无疑会使得语法变得更冗长,我们暂时不尝试解决这个问题。
注意到这会使得 fold
更合群。假设我们需要从一个数组中筛选出所有偶数并除以二,但想采用和 map
比较接近的格式。这时候我们需要的是 fold
:
1 | let n = input |
尝试一下用这种思路重写现有程序:
1 | factorList : Int -> [[Int]] |
变得更理想了!看来还是原始的 map
fold
系列好用!
C++
1 |
|