题解 ARC104F

发布时间 2023-08-03 09:58:45作者: Larry76

前言

在这里首先感谢一下题解区的 FZzzz,本人的题解思路主要是基于他并给出了自己的理解。

如非特殊说明,本题解中的数学符号原则上与题目中一致。

题目分析

需要转化的喵喵题。

我们需要把原问题转化成一个图论计数问题,然后剩下的就很好办了。

好,首先让我们修改一下题目的要求,将不存在的情况设为 \(p_i = 0\),这样就可以使得我们的 \(p_i\) 的值只可能取到自然数集合中连续的一段 \([0,n-1]\) 了。

考虑连边 \((i,p_i)\),我们首先能得到一个十分显然的性质,就是最终连边连出来的图必定没有环,证明显然,考虑偏序关系不允许出现环即可。

但是这个性质不是很强,我们还可以进一步得到相比更强的性质,就是连出来的图必定是一棵树,这个证明考虑 \(p_i\) 的值只会取到 \([0,i-1]\) 而已,又因为不会出现环,故现在此时连出来的是一棵树,并且是以 \(0\) 为根节点的树。

现在让我们观察一下每个节点上 \(h_i\) 的值,不难发现兄弟之间左方的兄弟的 \(h\)\(\le\) 右方的兄弟的 \(h\) 值,且当前节点的 \(h\) 值一定大于他的儿子们。证明显然,考虑如果左方的兄弟大于自己,则自己会被左方的兄弟支配,变成他的儿子,故左右兄弟之间是 \(\le\),考虑如果自己的儿子大于等于自己,那么它必定会成为自己的兄弟甚至是祖先的兄弟,故父亲儿子之间是 \(\gt\)

让我们定义 \(a_i\)\(i\) 左边第一个的兄弟,让 \(b_i\)\(i\) 最右边的儿子,设 \(c_i=\max\{c_{a_i} , c_{b_i} + 1\}\),则此时 \(c\) 必定是 \(h\) 的构造方案之一(证明考虑兄弟之间的偏序关系和父亲儿子之间的偏序关系),并且对于任意的 \(h\) 我们都有 \(h_i \ge c_i\),于是可以比较 \(c_i\)\(x_i\) 就可以看出 \(p\) 是否合法。

最后,设 \(dp_{i,j,k}\) 为区间 \([i-1,j]\) 形成了一棵树,且 \(c_{b_{i-1}} \le k\) 时,\([i,j]\) 的方案数,时间复杂度 \(\mathcal O(n^4)\)

代码实现

这里只给出了代码的关键部分,其余部分还恳请读者自行实现。

int n;

int X[MAX_SIZE];
int dp[MAX_SIZE][MAX_SIZE][MAX_SIZE];

void main() {
    n = read();
    for (int i = 1; i <= n; i++) {
        X[i] = read();
    }
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= n; j++) {
            dp[i + 1][i][j] = 1;
        }
    }
    for (int i = n; i >= 1; --i) {
        for (int j = i; j <= n; j++) {
            for (int k = 1; k <= n; k++) {
                for (int p = i; p <= j; p++) {
                    int q = min(k, X[p]);
                    dp[i][j][k] =
                        mt.add(dp[i][j][k],
                               mt.mul(dp[i][p - 1][q], dp[p + 1][j][q - 1]));
                }
            }
        }
    }
    printf("%lld\n", dp[1][n][n]);
    return void();
}