welikestudying的博客

博客

摩斯电码2.0(但是比官方题解详细一点点)

2024-08-08 10:47:54 By welikestudying

只要有信念,就一定能成功!

  • 加强前,这道题是一道不可多得的好题。
  • 加强后,这道题是一道在阳间不可多得的好题。

当然出到互测里还是显得太水了

题意

  • 下面定义 $w$ 为 $v_i,a_i$ 的值域范围。
  • 如果没有明确说明,下面的 $v_i$ 是指分配后的结果。

分析

一个显然的贪心思路是 $a_1,a_n$ 分配给 $v_1$,此后将不考虑这两个量。

发现该问题具有可二分性,二分答案 $k$ 之后问题变成:考虑无限可重集 $\{v_i/j\mid i\in[1,n],j\in\mathbf{Z^{+}}\}$让 $>v_1/k$ 的数个数最少。

对于一个设置完成的 $v_i$,它会给答案增加 $\lfloor (v_ik-1)/v_1\rfloor$ 的贡献,然后就有个 $01$ 背包的做法,设 $f(i,j)$ 表示考虑到前 $i$ 个数,给第 $i+1$ 个数留了 $j$ 张选票,$>v_1/k$ 的个数的最小值,直接这样暴力 DP,复杂度即为 $O(nw^2\log m)$,代码

额,出了点小 BUG,我们发现答案的上限不应该超过 $m$,所以实际上枚举答案才是更好的选择,设 $f(i,j)$ 表示考虑前 $i$ 个数,答案为 $j$,$>v_1/k$ 数的个数的上一轮留下的 $a_{i-1}$ 的最小值,暴力 DP,复杂度即为 $O(nmw\log m)$,代码

注意到你是枚举一个形如 $\lfloor (ax+b)/c\rfloor$ 的函数,只需要枚举到它 $\le m$ 的值,而且在 $\lfloor (ax+b)/c\rfloor$ 相同的时候应该尽量最大化 $x$,容易发现最大化的 $x'$ 满足: $$x'=\bigg\lfloor\frac{c\lfloor(ax+b)/c\rfloor+c-b-1}{a}\bigg\rfloor$$ 复杂度 $O(nm^2\log m)$,代码

转化思路:获得更好的做法

  • 由于某个奆佬想拿这个阴间思路出阴间题,所以这篇博客在写作的时候先隐藏了,如果这篇博客开放了,说明阴间题没出成,毕竟对于极逊队来说可能还是太水了
  • upd:这题出成了,但是被一堆奆佬爆踩的了。
  • 稍微提一下这个思路的发展历程:奆佬奆佬奆佬菜鸡
  • 简单介绍一下这玩意的复杂度:$O(n\log^3 m)$,某个阴间人物想到的阴间数据范围是 $n\le 10^4,1\le m,a_i,v_i\le 10^9$,时间限制 $2$ 秒。

你发现问题即我们要分配 $a_i$ 以最小化: $$\sum_{i}\bigg\lfloor\frac{v_ik-1}{v_1}\bigg\rfloor=\frac1{v_1}\bigg(\sum_{i}(v_ik-1)-\sum_i(v_ik-1)\bmod v_1\bigg)$$ 然后你发现问题变成了最大化 $\sum_i(v_ik-1)\bmod v_1$,可以采用传统的动态规划算法,但这里显然有更好的做法。

你发现对于任意一种可行解,对于 $v_i,v_{i+1}$,如果我们能够调整 $a_i$ 使得 $(v_ik-1)\bmod v_1$ 更大,那么这样做必然使得整体的答案不更劣,原因是显然的:假如我们使得 $(v_ik-1)\bmod v_1$ 增加了 $\Delta$,那么我们最坏的情况也只是使得 $(v_{i+1}k-1)\bmod v_1$ 减小了 $\Delta$,但实际上,由于取模的存在,$(v_{i+1}k-1)\bmod v_1$ 不一定能减小 $\Delta$(虽然在模 $v_1$ 意义下恰好“减了”$\Delta$),而这造成了答案的增加。

你发现这个性质实际上说明了按照如下的贪心可以构造出最优解:分配 $a_2$ 使得 $(v_2k-1)\bmod v_1$ 最大,在此基础上分配 $a_3$ 使得 $(v_3k-1)\bmod v_1$ 最大……这个朴素的贪心居然是正确的!采取合适的枚举方式,问题的复杂度即为 $O(nm\log m)$,代码

优化

我们的问题在于如何快速求解形如这样的问题: $$\max\{(ai+b)\bmod p\mid i\in[0,n]\}$$

  • 其实有很简单的方法可以做到 $O(\sqrt n\log n)$,代码,复杂度 $O(n\sqrt w\log w\log n)$。

二分答案 $k$,问题转化为计数: $$\sum_{i=0}^n[(ai+b)\bmod p\le k]$$ 艾弗森括号不太好处理,但是你发现: $$[x\bmod p\le k]=\lfloor x/p\rfloor-\lfloor(x-k)/p\rfloor$$ 因此现在问题变成一个经典的类欧几里得问题,计算: $$\sum_{i=0}^n\bigg\lfloor\frac{ai+b}p\bigg\rfloor-\sum_{i=0}^n\bigg\lfloor\frac{ai+b-k}p\bigg\rfloor$$ 因此我们就得到了此题 $O(n\log^3m)$ 的算法,你可以在这题看到类似的套路,代码

再优化

  • 目前的复杂度为 $O(n\log m\log n)$,原因是前面那个式子可以 $\log m$ 求,方法如下代码
  • 最后真正出出来的数据范围是:$n\le 10^5$,$m,a_i,v_i\le 10^9$。

如果不考虑类欧的问题,这个技巧其实在我们将枚举的 $O(w)$ 变成 $O(m)$ 的时候已经实现了,这其实算是一种简单拓展吧(然而你猜白糖怎么想到的?照着类欧的式子瞎推推出来的,因此在实际过程中困难了许多,还是推荐这个翻转上下然后利用单调性压缩的思想理解)。

花絮

在正解是 $O(n\log^3m)$ 算法的时候,我们曾经采取过多种方法卡常,主要是外层二分算上下界可以减半常数(随机数据下 $\log$ 可以消掉,不过我们针对它进行了数据的加强),内层二分适当使用插值查找也可以加速。

有两个做法在纯随机大数据下几乎必然正确,一个是 $O(n)$ 算法,代码,一个是 $O(n\log m)$ 算法,代码

其中后一种做法较为难卡,为了卡掉后一种做法(以及它可能的随机化以及数据范围分治版本)……我们差点放弃……不过最后找到了一种足够强度的随机方式能稳定卡它,但是它对小数据不起效果,对于小数据我们是专门对着撞的。

另外,我的代码被某位大佬 hack了,具体原因是在累计变量中爆了长整型,已经修改,作者为自己代码在如此重要的场合对大家可能进行的误导深表歉意。

在本次集训队互测中,一共有两人场切了此题,一人似乎被卡常了(可惜了,虽然本人实现的代码并没有经过任何的常数实现优化)(似乎还有几位奆佬不屑于做此题 QwQ),请允许我向他们致以敬意。

同样对哪些在场上的跟正解类似但又不尽相同的做法感兴趣,若我真能抽出时间,或许会讲一讲好的做法吧。

Comments

welikestudying
然而他们的代码我也弄丢了,来不及看了。
  • 2024-08-11 09:50:55
  • Reply

Post a comment

You can use @mike to mention the user mike.

If you wish to input the '@' character, please use @@