首先根据 Dliworth 定理,原问题等价于前缀 LIS。
考虑如何做到 \(O(n^2)\) 求出 LIS 的变化点(显然这只有 \(n\) 个)。按照值从小到大考虑,记 \(f_{i,j}\) 表示考虑到第 \(i\) 个值,长度为 \(j\) 的 LIS 最早在哪个前缀处出现,转移只需要 two-pointers 一遍就能更新。
这个转移的实质是:考虑这个值在原序列中出现的位置 \(p\),从大到小,依次找到 \(f_i\) 中第一个 \(\geq p\) 的点更新成 \(p\)。归纳一下可以说明,每种值的位置在 \(f\) 中出现的是一个前缀。也即,若 \(p+kn\) 出现了,\(p+(k-1)n\) 一定出现。
则我们可以改成记 \(c_i\) 表示第 \(i\) 个位置上的值出现了几次,然后考虑转移,假设当前值出现的位置是 \(x\),考虑 \(i=x+1,x+2,\dots n\),若 \(c_x<c_i\),则交换 \(c_x,c_i\)。
将 \(c_x\) 加一后对 \(i=1,2,3,\dots x-1\) 做同样的操作。
容易发现 \(\sum c=n\),且 \(c_x\) 每次操作都会增加,因此总共只会更新 \(c_x\) \(O(\sqrt n)\) 次,用线段树找到这些位置即可做到 \(O(n\sqrt n\log n)\),然后在 ex_test 6 T 飞了
正确的做法是用 set 维护每种出现过的值以及出现的位置,然后查询的时候在每个 set 里面 lower_bound。这样的复杂度是 \(O(\sum \log siz_i)\),其中 \(siz_i\) 是 \(c\) 的值为 \(i\) 的出现次数,要满足 \(\sum isiz_i\leq n\)。这个复杂度相当于 \(O(\sum\limits_{i}\sum\limits_{j}[siz_j>2^i])\leq O(\sum \limits_{i}\sqrt\frac{2n}{2^i})=O(\sqrt n)\),于是就可以通过了。
标签:25,limits,siz,sum,sqrt,UR,LIS,UOJ,出现 From: https://www.cnblogs.com/275307894a/p/18279857