CF2060FG 题解
F G
F. Multiplicative Arrays
组合数学,dp
好题。一开始尝试从质因数分解的角度考虑,但并没有找到比较好的刻画方式。
首先观察发现序列中只有至多 \(\lfloor \log_{2} k \rfloor\) 个位置不为 \(1\),所以先考虑不为 \(1\) 的位置,再考虑往序列中加入 \(1\) 对答案的贡献。
我们想要计算当序列长度为 \(i\) 时,序列中元素之积为 \(j\) 的方案数。这个问题可以用 dp 解决(记住:dp 是解决计数问题的有力手段!)。
设 \(f(i, j)\) 表示长度为 \(i\) 且元素之积为 \(j\) 的序列个数。考虑在序列末尾加入一个新元素 \(d\),得到转移方程为:
初始化 \(\forall j \ge 2\),\(f(1, j) = 1\)。
根据观察,\(i\) 只用枚举到 \(\lfloor \log_{2} k \rfloor\)。对 \(j\) 这一层的转移相当于枚举 \(k\) 以内正整数的所有倍数,根据调和计数的分析,单层转移的时间复杂度为 \(O(k \log k)\),所以总时间复杂度为 \(O(k \log^{2} k)\)。
然后考虑怎么统计答案。
对于 \(x\),首先枚举序列长度 \(1 \le m \le n\),然后枚举不为 \(1\) 的元素数量 \(i\):
这个式子不太好优化。考虑交换求和顺序:
第二个等式提出了无关 \(m\) 的量 \(f(i, x)\),第三个等式是上指标求和。这样就可以直接计算了。
需要注意的是组合数的计算:\(n\) 太大没法预处理,但可以预处理 \(k\) 以内的阶乘逆元,然后组合数用下降幂算。
AC 记录
G. Bugged Sort
神题。
这种乍一看没什么思路的题还是要多发掘操作的性质。本题中可以观察到以下结论(证明见 官方题解):
- 对每个 \(i\),\((a_{i}, b_{i})\) 都不会解绑。所以一次对 \((i, j)\) 的操作实际上可以看作:交换两个数对,然后分别翻转两个数对。(翻转数对 \(i\) 代表交换 \(a_{i}\) 和 \(b_{i}\)。)
- 可以在不翻转的情况下交换两个数对。
- 可以在不改变位置的情况下翻转两个数对。
- 不可以在不改变位置的情况下翻转一个数对。
根据性质 \(2\),可以先把所有数对按某种方式排序。可以证明如果序列最终有序,则 \(\min(a_{i}, b_{i}) < \min(a_{i + 1}, b_{i + 1})\),所以就按这种大小关系排序。之后要判断的就是:每次选择两个数对翻转,最终能否使两个序列都有序。
还是用 dp 解决。
设 \(f(i, 1/0, 1/0)\) 表示对于前 \(i\) 个数对,在翻转/不翻转 \(i\),且翻转数对的总数为奇数/偶数的情况下,能否使前 \(i\) 个数对满足。枚举翻转数对的奇偶性 \(o \in \{0, 1\}\),然后分类讨论是否翻转 \(i\),是否翻转 \(i + 1\),得到 4 个转移方程(为了方便,下文中 \(a \gets b\) 表示 \(a \gets a \or b\)):
- 不翻转 \(i\) 也不翻转 \(i + 1\):\(f(i + 1, 0, o) \gets f(i, 0, o) \and (a_{i + 1} > a_{i}) \and (b_{i + 1} > b_{i})\)。
- 其它三种情况类似。
初始化 \(f(1, 0, 0) = f(1, 1, 1) = 1\),答案为 \(f(n, 0, 0) \or f(n, 1, 0)\)。
AC 记录