为什么有人能推导出第三题却不能推导出签到题(⊙_⊙)?
有一棵树,有根\(T\)。从根节点开始,在点\(u\)处,设置点\(u\),并且有\(d\)没有被访问过 如果 的儿子的概率走向未访问过的儿子。从根节点向上走结束步行。
注\(f(T)\)是这样一次行走所到达的点的深度总和的期望。
给定 \(N\)(\(N\le10^7\)),对于 \((1,2,\dots,N) 对于\)\(P\)的所有排列,构建一个具有小根\(T_P\)的笛卡尔树,并找到
答案是给定正整数的模 \(mod\) (\(n\lt mod\le2\times10^9\)), \ ( mod\) 不一定是素数。
首先分析\(T\)上的行走方法。笛卡尔树是二叉树。如果当前点有一个未访问过的儿子,则:
所以我们发现,不管儿子有多少个,得到儿子的概率总是\(\frac12\),这会让我们后续的推导变得容易很多。
考虑到笛卡尔树本身是一种分而治之的结构——将最小值分为两个区间分别构建笛卡尔树,而对于一个排列来说建立笛卡尔树只与元素个数有关在安排中。由此,您可以设计一个以排列元素的大小作为状态的DP。
设 \(g_n\) 表示“\(n\) 元素\(P_n\)”的所有排列 构建笛卡尔树 \(T_{P_n}\),\(f(T_{P_n})\)"、\(g_N\)之和就是我们所需要的回答。然而,深度之和并不容易直接计算(虽然可以使用期望的线性度将其拆分为单点贡献,但后续的推导会绕一个大圈,这不像下面的方法那么直观) 。
有一个非常常用的属性:\(\sum dep=\sum siz\),所以设计辅助DP\(f_n\)的意思是“对于” \ (n\) 元素的所有排列 \(P_n\) 构建笛卡尔树 \(T_{P_n}\),起始预计达到多少个从根点开始”。
传输考虑枚举左子树\(l\)的大小,并选择左子树\(\binom{n-1}{l}\)的元素。利用期望的线性度,左子树的贡献是 \(f_l\) 乘以右子树的选项数量。一种排列显然对应于笛卡尔树,因此贡献为 \(f_l\times(n-l-1)\)。右子树也是如此,最后还要加上根的贡献。对于\(n!\),笛卡尔树根的贡献为\(1\)。
忽略\(g_n\),继续推导\(f_n\)的公式:
这么多阶乘很容易让人想起指数生成函数,不妨改成:
显然我们可以将\(\frac{f_n}{n!}\)视为一个整体,发现转账的主体是一个前缀和。令 \(F_n\) 为 \(\frac {f_i}{i!}\) (\(i\ge1\) 的前缀和) ,那么公式可以简化为:
\(F_0=0\),经过多次迭代,可得到\(F_n\)的通项。
在调和级数之前有一个类似于术语\((n+1)\)的内容。设调和级数之前的项\(n\)为\(H_n\)。
现在回头看\(g_n\),近似传递与\(f_n\)相同,但根的贡献是\( f_n\),即\(siz_n\)的期望值(所以首先推导\(f\))。
同样,我们记住\(G_n\)作为\(\frac{g_i}{i!}\)的前缀和,并把\( (1)\) 替代。
迭代\((2)\)还可得到\(G_n\)的通式:
我们要计算的答案是\(g_n=n!(G_n-G_{n-1})\),因为\(mod\)不一定是一个素数,那么我们还要继续推公式。
这样分母就可以全部抵消了。在对调和级数进行预处理之前,\(n\)的系数的前缀和和后缀和可以通过 \(\mathcal O(n)\) 来求解。
/* Lucky_Glass */
#包括
#包括
#包括常量 int N = 1e7 + 10;
typedef 长长长;
整数模;
内联 int reduce(长键) {
return int((key %= mod) < 0 ? key + mod : key);
}
int pre[N], suf[N];
int main() {
freopen("笛卡尔.in", "r", stdin);
freopen("cartesian.out", "w", stdout);
整数 n; scanf("%d%d", &n, &mod);
前[0] = 1;
for (int i = 1; i <= n; ++i) pre[i] = reduce(1ll * pre[i - 1] * i);
suf[n + 1] = 1;
for (int i = n; i; --i) suf[i] = reduce(1ll * suf[i + 1] * i);
整数 ans = 0;
for (int i = 1; i <= n; ++i)
ans = reduce(ans + 1ll * pre[i - 1] * suf[i + 1]);
int ex_ans = 0;
for (int i = 2, tmp = 0; i <= n; ++i) {
tmp =减少(pre[i - 2] + (i - 1ll) * tmp);
ex_ans = reduce(ex_ans + 1ll * tmp * suf[i + 1]);
}
ans = reduce(1ll * ans + ex_ans);
printf("%d\n", ans);
返回0;
}
霓虹中错落影像
满城声色褪色去喧闹
废墟上余文几行
未铭记何淡谈忘
——《岁月成碑》乐正绫/天
>链接时间已过 - 网易云