、

P16433 [APIO 2026 中国赛区] 上升

题目大意

给定一个有了一部分元素的排列,定义一个排列的价值是

\[\prod_{i=1}^{n-1}([p_i<p_{i+1}]w_i+[p_i>p_{i+1}]) \]

求所有完整排列价值之和。保证给出的元素构成一个上升子序列。

要求不能出现任何除法操作。

\(n\le 500\)

思路

首先我们不希望既考虑小于的情况又考虑大于的情况。所以我们去考虑将其转化为

\[\prod_{i=1}^{n-1}([p_i<p_{i+1}](w_i-1)+1) \]

令 \(w_i^\prime=w_i-1,S=\{i|p_i<p_{i+1}\}\),则

\[\prod_{i\in S}(w_i^\prime+1) \]

根据组合意义等价于这个位置可选可不选:

\[\sum_{T\sub S}\prod_{i\in T}w_i^\prime \]

那么等价于考虑整个排列所有上升子序列的乘积之和。

之后我们考虑全 \(0\) 和不全 \(0\) 的区别在于两个确定元素之间的个数是已经确定的了,所以我们在 dp 的时候不能保证中间一定最终有这么多个元素。

我们考虑的解决方法是设计一维状态表示当前填了几个大于前一个限制的数,记为 \(l_i\)。那么这样我们就可以确定两个位置之间还有几个数填进去还会对最终的答案有贡献。

之后我们需要维护填入的数之间的相对大小,如果一个数小于等于 \(l_i\),我们需要记录比它小的数还有几个可以填,这样就可以排列组合出会有几个填进去能够产生贡献了。记为 \(f_{i,j,k}\)。

对于大于 \(l_i\) 的数,我们可以直接记录它的排名来知道这样比它小的已填的都会产生贡献。记为 \(g_{i,j,k}\)。

对于有了值的位置 \(i\),那么这里 \(l_i=p_i\le l_i\),故只有 \(g\) 会被更新。

首先,对于上一位的 \(g\) 全部都可以被更新,因为它们已经小于等于上一个 \(l\) 了,而题目保证 \(l\) 递增,故全部都会产生贡献。

那么剩下的对于 \(f\) 的情况我们只需要维护排名,而在更新的时候选择比当前 \(g\) 的排名大的数即可。可以通过前缀和维护。

然后因为是固定数,所以在枚举两个排名的时候中间会有一些位置是需要放 \((l_{i-1},l_i)\) 之间的数,然后可以认为这些数之间的相对顺序被更新的 dp 值确定,我们只需要知道究竟应该是哪些值即可。所以乘上一个组合数 \(\binom{r_{i-1}-r_i}{l_i-l_{i-1}-1}\),其中 \(r_i\) 指有多少个数比 \(l_i\) 大。

之后对于随便填的位置,我们考虑填大数还是小数。

对于小数转移小数的情况,我们考虑类比上面的前缀和去维护排名比当前大的做转移。对于小数转移大数的情况,发现全部都可以有贡献,那就是所有前置 \(g\) 状态乘上 \(w_i\) 即可。

对于大数转移小数,不存在贡献,直接继承前面的所有状态即可。对于大数转移大数也是前缀和找排名大的转移即可。

这样就只使用了前缀和,时间复杂度 \(O(n^3)\)。

posted @ 2026-09-24 14:44  tanghg  阅读(7)  评论(0)    收藏  举报