[题解] [AGC024E] Sequence Growing Hard
Yansuan_HCl · · 题解
UPD 24/12/13 修正笔误:
即每次插入一个数,使得每次操作后序列的字典序大于操作前的数组。观察发现,一个数只有插入在小于它的数前面,或插入在序列尾,才一定能使字典序变大。可以在序列尾放一个无穷小的虚点,方便实现。
考虑怎样计数操作,不会做。试想更简单的问题:对于一个确定的序列,怎样刻画“插入”操作并对其计数?根据性质,一个数会插入在另一个数前。因此,可以考虑向位置靠后的数连边。这样,每个位置都有一个出边,只有虚点没有出边。所以这是一棵树,树上每个节点的父亲的权值都严格小于它。
这样,对于确定的序列,一个插入方案可以被写成一棵树,一棵确定的树也就可以对应一个插入方案。不交子树之间,贡献互不影响。于是转化为计树。
计树题就可以比较方便地做。设
。其中组合数表示:钦点完根和加入子树的根,剩下的时刻选一些时刻放入操作。
于是就可以 DP. 进行后缀和优化之后复杂度为
const int N = 305;
int n, m; ll P;
ll C[N][N];
ll f[N][N], s[N][N];
int main() {
rd(n, m, P);
U (i, 0, N - 1) {
C[i][0] = 1;
U (j, 1, i)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;
}
U (k, 0, m) f[k][1] = 1;
D (k, m, 0) s[k][1] = (s[k + 1][1] + f[k][1]) % P;
// f_k(i+j) <- f_k(i)f_{k' > k}(j) * C_{i-2+j}^{j}
// f_k(i) = \sum_{x+y=i, x,y>=1} f_k(x) * s_{k+1}(y) * C_{i-2}^y
U (i, 2, n + 1) {
U (k, 0, m)
U (x, 1, i - 1)
(f[k][i] += C[i - 2][x - 1] * f[k][x] % P * s[k + 1][i - x]) %= P;
D (k, m, 0) (s[k][i] = s[k + 1][i] + f[k][i]) %= P;
}
printf("%lld", (f[0][n + 1] % P + P) % P);
}