ABC405G

记一道非常具有教育意义的题目。题目大意是给你一个大小为 NN 的数组和 QQ 次询问,询问的结构是 L,R,XL,R,X ,需要求出 [L,R][L, R] 中小于 XX 的数任意排列能组成多少种不同的序列。

首先很容易想到的是维护xx出现的次数,记为 cxc_x 。所求答案就是 (i=1X1ci)!i=1X1ci!\frac{(\sum\limits_{i=1}^{X-1}c_i)!}{\prod\limits_{i=1}^{X-1}c_i!} 。不考虑 XX ,想一想该怎么维护这个答案,对于每个区间直接维护 cc 是很困难的,否则会在计算答案的时候因为 XX 太大爆炸。同时发现加入一个数是可以直接 O(1)O(1) 维护贡献的,所以想到直接维护乘积,记为 prodprodcc 数组,查询可以用莫队做。

现在考虑 XX 的限制,查询答案的时候对应 XX 直接用权值树状数组查询数量和乘积逆元就行,但是这样还是有一个问题,多了个 log\log 会 T。

这个问题和一般的莫队的区别在于多了一个 XX,导致需要动态修改/查询。现在就是要把这个动态修改/查询的部分优化到 O(1)O(1) 。把修改和查询分开来考虑,修改做了NQN\sqrt Q次,查询做了 QQ 次。修改部分需要 O(1)O(1),查询的限制放宽到根号级别。因为是单点修改,想到用分块来做。

具体思路是:

  • 修改:更新 prodprodcc 数组
  • 查询:累计 prodprodcc 数组,分块查询

具体实现的过程中产生了许多卡常问题。首先是直接用逆元做除法的时候会产生一个 log\log,导致 T 了好多次。正确做法是预处理阶乘的逆元。同时莫队的实现中需要采用奇偶块优化卡卡常,因为之前没有被卡过所有一直没有学这个技巧,实际上很简单:朴素做法存在每个块都要让 rr 指针回到最小的位置的缺陷,实际上 rr 的顺序不关键,只要能保证线性移动就行。这个时候考虑到上一个块的 rr 指针会在比较后面的位置,倒着排序这个块的 rr 就可以从后往前扫卡卡常,下一个块再从前往后交替做就行。


电波交流