题解 CF653G Move by Prime
容易想到每个质数分开处理,每次操作就是次数加一或减一,目标就是让它们全部相等。
这是经典小学奥数问题,抽象成数轴上的点,找到一个点使该点到其余所有点距离和最小。首尾分组,容易发现这些点全部跳到中位数时最优。
令 \(x_i\) 表示次数从小到大排序后第 \(i\) 大的数,\(M(x)\) 表示子序列中 \(x_i\) 的中位数。
那问题转化为对所有子序列 \(\sum|x_i-M(x)|\) 求和。
简单,\(M(x)\) 必定互相抵消。对于所有 \(x_i\) 考虑其贡献。
用 \(j\) 表示比 \(x_i\) 小的选了几个数,\(k\) 表示比 \(x_i\) 大的选了几个数,分类讨论一下:
-
若 \(j<k\),说明中位数比 \(x_i\) 大,贡献为 \(-x_i\)。
-
若 \(j=k\),说明中位数等于 \(x_i\),贡献为 \(0\)。
-
若 \(j>k\),说明中位数比 \(x_i\) 小,贡献为 \(x_i\)。
对于某些相等的 \(x_i\),不用在意它们是否会使答案计算产生错误,因为会互相抵消。于是可以认为 \(\forall j\in[1,i),x_j<x_i\) 且 \(\forall j\in(i,n],x_j>x_i\),尽管某些 \(x_j\) 和 \(x_i\) 相等。
所以 \(x_i\) 对答案贡献为
这是组合数卷积的形式,尝试往范德蒙德卷积上靠,先考虑左边的系数。
尝试枚举 \(j+k\) 发现区间是 \([j,2\times j-1]\),两个端点都是动的,这个不好。换枚举 \(j-k\),区间是 \([1,j]\),这个好。
令 \(d=j-k\),有
同理有
所以 \(x_i\) 对答案的贡献为
预处理组合数前缀和即可做到 \(O(1)\) 计算,因为 \(3\times 10^5\) 以内的数最多有 \(6\) 个不同质因数,所以 \(x_i\ne 0\) 的位置总共不超过 \(6n\) 个,直接做最坏也就 \(O(n\log w)\),可以通过。
或者说用 \(f_i\) 表示 \(x_i\) 的系数,对于相等的 \(x_i\) 一块考虑,贡献为一段连续的 \(f_i\),预处理 \(f_i\) 的前缀和即可。复杂度瓶颈在枚举 \(p^k\) 的倍数,这是 \(O(w\log \log w)\) 的。

浙公网安备 33010602011771号