CF 1946 F

一道好题。

  • 一定要好好读题,不要看漏。

一个非常非常重要的条件是,\(a\) 是一个排列。这就说明可能会有调和级数之类的做法了。

  • 考虑怎么处理询问 \([l,r]\) 之类的东西。

有一个普遍的思路,就是 \(ans=sol(r)-sol(l-1)\),但是我们发现并不适用。因此朴素的 \(f_i\) 表示 \(1\sim i\) 的答案就可以了,我们必须再加一维状态,设 \(f(l,r)\) 为起点在 \(l\),终点在 \(r\) 的方案数。

如果我们有了 \(f(l,r)\),那么一次询问 \([ql,qr]\) 是要求 \(\sum_{x\ge ql,y\le qr}f(x,y)\) 的和,其实就是一个二位数点问题。

  • 考虑非 \(0\)\(f(l,r)\) 有几个。

因为起点终点固定,那么一定 \(a_l\mid a_r\)。所以合法数量是 \(\sum div(n)\) 个,也就是调和级数 \(\mathcal{O}(n\ln n)\) 级别。

  • 对于单个的 \(f(l,r)\),怎么求。

可以固定左端点或者右端点。固定左端点 \(l\) 更加容易,因为合法的右端点 \(r\) 是找到 \(a_l\) 的倍数,而不是找 \(a_r\) 的因数。转移方程是 \(f(l,r)=\sum_{r'<r}f(l,r')[a_{r'}\mid a_r]\)。但是这个又要找因数了,所以考虑把习惯的 pull 改成 push,即对于 \(f(l,r)\) 考虑他的贡献。这样,他对 \(f(l,r')\) 其中 \(a_r\mid a_{r'},r<r'\) 有贡献。

因此我们有了一个 \(\mathcal{O}(n\ln^2n)\) 的做法。

  • 二维数点的写法。

可以无脑的全部离线下来排序以后 bit 维护,但是发现其实可以从大到小枚举 \(f(l,r)\)\(l\) 的过程中就把他解决掉,这样常数较小并且空间小、更好写。

因此得到了一个时空较为优秀的做法。

submission

posted @ 2024-09-22 22:48  SFlyer  阅读(29)  评论(0)    收藏  举报