LGP7521 [PUTS 2021-B] 取模 学习笔记
LGP7521 [PUTS 2021-B] 取模 学习笔记
前言
妙妙题。
题意简述
给定 \(n\) 个正整数 \(a_i\)。请选出三个数 \(a_i,a_j,a_k\),最大化 \((a_i+a_j)\bmod a_k\)。
\(3\le n\le 2\times 10^5\),\(a_i\le 10^8\)。
做法解析
你看到这个题要选取三元组的同时数据范围还开到了 \(2\times 10^5\)。“我打两劳嗝,真的假的?”
别急。先考虑考虑 \(O(n^2)\) 上下的东西试试。你可能会想着先把所有 \((a_i+a_j)\) 预处理出来,但是接下来你在枚举 \(a_k\) 的时候就犯难了,因为你不太容易在 \(O(n)\) 左右找出来对 \(a_k\) 最优秀的 \((a_i+a_j)\)。一个原因是这些 \((a_i+a_j)\) 的值域太大,你不知道对它们的取模要减掉几个 \(a_k\),也就不好讨论问题。
于是你转身向枚举 \(a_k\) 走去,问题一下豁然开朗:因为你最外层枚举 \(a_k\) 的话,就可以 \(O(n)\) 先把每个 \(a_i\) 变成模 \(a_k\) 意义下的,这样 \((a_i+a_j)\) 的值域就缩到了 \([0,2\times a_k)\)。
那我们就经典地分类讨论。\(a_i+a_j<a_k\) 时,要最大化答案我们就用双指针扫一遍(这个不需要我教吧)。\(a_i+a_j>a_k\) 时候我们直接选最大的两个 \(a_i\) 就行了(显然 \(a_i+a_j\) 不可能在取模时被减去两个 \(a_k\),所以这是对的)
好了,现在我们已经可以 \(O(n^2\log n)\) 干掉此问题了。正解是什么?
不知道,除了剪枝之外我找不到任何本质优化。
第一个剪枝是我们每种 \(a_k\) 只考虑一遍。
无事发生,似乎。
第二个剪枝是我们从大到小枚举 \(a_k\),如果当前答案未能更新之前答案就直接break。
无事发生……吗?
好了,我们现在的时间复杂度来到了 \(O(n\log n\log V)\)。
为什么?
不妨认为原序列元素没有重复。可以写出下柿:
由于 \(ans\) 是最优答案,所以有:
又显然有 \(a_i+a_{i+1}<2a_{i+2}\),所以 \(\bmod\) 最多减一个 \(a_{i+2}\),可以把上面的柿子换成 \(a_i+a_{i+1}-a_{i+2}\le ans\)。进一步将柿子变形可得:
然后拿 \(h_i=(a_i-ans)\) 代换掉可得:
浙公网安备 33010602011771号