user
1 | 快速中位数 |
gemini-fast
1 | 你的思路非常清晰:预计算数列 + 对顶堆(双优先队列)+ 滑动窗口是解决这类动态中位数问题的经典高效方法。不过,针对 $n = 10^7$ 和 $k = 10^5$ 的超大规模数据,我们需要注意以下几点以优化性能:素数预计算:第 $10^7$ 个素数大约在 $1.7 \times 10^8$ 左右,需要使用高效的线性筛(欧拉筛)。快速幂:计算 $(p_k)^k \pmod{10007}$ 时,利用模运算性质。由于 $10007$ 是素数,根据费马小定理,$a^k \equiv a^{k \pmod{10006}} \pmod{10007}$,这能显著提速。滑动窗口优化:std::priority_queue 不支持任意元素的删除。为了实现滑动窗口,我们可以使用 std::multiset 配合中位数迭代器,或者使用带懒惰删除的堆。考虑到 C++ 的 std::multiset 稍微有点慢,用两个 std::multiset 维护中值平衡是比较稳妥的写法。C++ 代码实现 |
1 |
|
1 | 关键细节说明内存压力:$10^7$ 个 int 占用约 40MB,S 和 S2 数组加起来不到 100MB。但 is_prime 数组在 $1.8 \times 10^8$ 长度下占用较大(约 180MB),如果内存受限,建议使用 std::vector<bool> 或 std::bitset。中位数的逻辑:如果 $k$ 是奇数,中位数是排序后的第 $(k+1)/2$ 个数。如果 $k$ 是偶数,中位数是第 $k/2$ 和第 $k/2 + 1$ 个数的平均值。性能瓶颈:std::multiset 的插入和删除是 $O(\log k)$,总复杂度为 $O(n \log k)$。对于 $10^7$ 的量级,运行时间可能在数十秒到两分钟之间。进一步优化的建议如果追求极致性能,由于 $S_2$ 的值域非常小(最大约为 $10007 \times 2 = 20014$),你可以放弃堆结构,转而使用 树状数组 (Fenwick Tree) 或 桶 (Bucket) 来维护频率:建立一个大小为 20015 的桶,记录当前窗口内每个数字出现的次数。使用树状数组维护前缀和,通过二分查找或树状数组上倍增找到第 $k/2$ 小的数。这种方法的复杂度将降至 $O(n \log(\text{max\_val}))$,在 $n=10^7$ 时会比 multiset 快得多。你想尝试用树状数组(速度更快)的方案重写这部分计算逻辑吗? |