loj3395 - Yet Another Permutation Problem 题解

哎,没题解的题真是害人,tm 一个下午就直接砸在这上面了。


先分析对于某个 \(k\),哪样的排列会被算。每次操作就是把一些元素抽出来扔到开头或末尾,那么没被动的元素肯定是连续一段区间且保持原顺序不变的。也就是被算的排列一定存在一个长度为 \(k\) 的上升子段。那么这个条件是否充分呢?容易构造,就反过来把左右的元素塞回去。

那么就是要求最长上升子段大于等于 \(k\) 的排列数量。考虑枚举长度为 \(k\) 的上升子段的位置,但一个合法的排列可能有多个这样的位置,不难想到容斥。就是对每个位置,搞个当前位置的长度等于 \(k\) 的子段是上升字段的排列集合,那么答案显然就是这些集合的并的大小,那就搞容斥。

那么对于一个位置集合,把每个位置往后伸 \(k\),可能形成重叠,那就连起来了,最后变成若干个相连的区间 \([l_i,r_i]\),要求每个区间内都上升。这样的排列有多少呢?很简单,就是 \(\dbinom n{r_1-l_1+1}\dbinom{n-(r_1-l_1+1)}{r_2-l_2+1}\cdots\),就对把没包含在区间内的元素看成单独的区间,给每个区间分配元素。组合数拆一下约一下等于 \(\dfrac{n!}{\prod(r_i-l_i+1)!}\)

容易发现这个贡献仅和 \(\{[l_i,r_i]\}\) 相关,直接针对位置集合搞反而没前途。于是我们针对这个区间序列搞,贡献是固定的,那就看能够连成这个局势的所有位置集合的容斥系数之和。那显然每个区间是独立的,每个区间内就是要搞若干个位置使得它们恰好重叠形成该区间。这个有点不显然,先暂时设长度为 \(i\) 的区间的这样的容斥系数之和为 \(f_{i,k}\)。由于每个区间是独立的,每个区间内找出一种方案容斥系数相乘再相加,乘法分配律拆出来发现就是 \(\prod f_{r_i-l_i+1,k}\)。那么一个区间序列的贡献就是 \(n!\prod\dfrac{f_{r_i-l_i+1,k}}{(r_i-l_i+1)!}\)

那么此时不难搞出一个线性 DP 来计算所有区间序列的贡献了。设 \(dp_i\) 表示考虑到第 \(i\) 的结果,边界 \(dp_0=1\),转移方程显然 \(dp_i=\sum\limits_{j=k}^i\dfrac{f_{j,k}}{j!}dp_{i-j}\),答案 \((1-dp_n)n!\)。先假设把所有 \(f\) 值求出来了,那么这是个分治 FFT 的形式,直接分治 FFT 总复杂度是平方二次对数,求逆是平方对数,可是鄙人不会多项式呀。况且我们 \(f\) 还没求出来,先求一波再说。

一个区间设为 \([1,i]\),那么 \(i-k+1\) 肯定是要选的对吧。选了之后,发现只要往前相邻两个位置距离不超过 \(k-1\) 并且开头在 \(1\) 就行了。不难列出转移,设 \(g_{i,k}=-\sum\limits_{j=1}^kg_{i-j,k}\),那么 \(f_{i,k}=\begin{cases}0&i<k\\-g_{i-k,k-1}&i\geq k\end{cases}\)。那么现在 \(f\) 求出来了(对 \(g\) 可以前缀和优化),但还是需要求逆。不妨打个表或者手玩玩 \(f\),可以发现 \(f\) 优美的性质(循环节):\(k=1\) 时除 \(i=1\) 全为 \(0\)(由于这种情况特殊,直接输出 \(n!\) 特判掉);\(k>1\) 时从 \(i=k\) 往后每 \(k\) 个一循环,每个循环节开头两个是 \(1,-1\),其它都是 \(0\)。可以发现大量有 \(0\) 的元素,更具体的,对特定的 \(k\) 只有 \(\mathrm O\!\left(\dfrac nk\right)\) 个非零元素。那么 DP 转移的时候只需要找非零的地方即可,复杂度分析出来是个调和级数——平方对数的,就可以过了。

这题模数输入,可以用一下快模,虽然也只快了 400ms,而且不知道有啥意义(((code

posted @ 2021-04-15 22:29  ycx060617  阅读(317)  评论(0编辑  收藏  举报