「SOL」打扫笛卡尔cartesian (模拟赛)
为什么会有人推得出来第三题想不出来签到题啊 (⊙_⊙)?
题面
有一棵有根树 \(T\)。从根节点出发,在点 \(u\) 时,设点 \(u\) 还有 \(d\) 个未访问过的儿子,则有 \(\frac1{d+1}\) 的概率向上(深度较小的方向)走一步,有 \(\frac1{d+1}\) 的概率走向一个未访问过的儿子。从根节点往上走则结束游走。
记 \(f(T)\) 为这样游走到达的点的深度之和的期望。
给定 \(N\)(\(N\le10^7\)),对 \((1,2,\dots,N)\) 的所有排列 \(P\),建立小根的笛卡尔树 \(T_P\),求
\]
答案对给定的正整数 \(mod\) (\(n\lt mod\le2\times10^9\))取模,\(mod\) 不一定是质数。
解析
先分析在 \(T\) 上的游走方法。笛卡尔树是二叉树,若当前点有未访问的儿子,则:
- 只有一个儿子时,有 \(\frac 12\) 的概率会走向该儿子;
- 有两个儿子时,有 \(\frac 13\) 的概率第一次就走向该儿子,有 \(\frac 13\times\frac 12\) 的概率第二次走向该儿子,即总共有 \(\frac 12\) 的概率会走向该儿子。
于是我们发现是否会到达一个儿子的概率恒为 \(\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\) 的式子:
f_n&=n!+\sum_{l=0}^{n-1}\binom{n-1}{l}(n-l-1)!f_l\\
&=n!+\sum_{l=0}^{n-1}(n-1)!\frac{f_l}{l!}
\end{aligned}
\]
这么多阶乘容易让人联想到指数生成函数的样子,不妨化一下:
\]
显然可以把 \(\frac{f_n}{n!}\) 看成一个整体,发现转移式的主体是一个前缀和。记 \(F_n\) 为 \(\frac {f_i}{i!}\) (\(i\ge1\))的前缀和,则式子可以简化为:
\]
\(F_0=0\),多次迭代过后可以得到 \(F_n\) 的通项。
\]
有一个类似于调和级数前 \((n+1)\) 项的东西,设调和级数前 \(n\) 项为 \(H_n\)。
F_n=(n+1)(H_n-1)&\tag{1}
\end{align}
\]
现在回头看一看 \(g_n\),大致转移与 \(f_n\) 相同,但是根的贡献是 \(f_n\),也即 \(siz_n\) 的期望值(所以先推导 \(f\))。
g_n&=f_n+\frac12\sum_{l=0}^{n-1}\binom{n-1}{l}\Big((n-l-1)!g_l+l!g_{n-l-1}\Big)\\
&=f_n+\sum_{l=0}^{n-1}\binom{n-1}{l}(n-l-1)!g_{l}\\
&=f_n+\sum_{l=0}^{n-1}(n-1)!\frac{g_l}{l!}\\
&=n!+\sum_{l=0}^{n-1}(n-1)!\frac{g_l+f_l}{l!}
\end{aligned}
\]
同样的,我们记 \(G_n\) 为 \(\frac{g_i}{i!}\) 的前缀和,把 \((1)\) 代入。
G_n-G_{n-1}&=1+\frac 1n(F_{n-1}+G_{n-1})\notag\\
&=H_n+\frac 1nG_{n-1}&\notag\\
\to G_n&=H_n+\frac{n+1}{n}G_{n-1}&\tag{2}
\end{align}
\]
对 \((2)\) 进行迭代也可以得到 \(G_n\) 的通项公式:
\]
我们要算的答案是 \(g_n=n!(G_n-G_{n-1})\),由于 \(mod\) 不一定是质数,那还得继续推式子。
g_n&=n!\Big(H_n+\sum_{i=1}^{n-1}\frac{H_i}{i+1}\Big)\\
&=n!H_n+n!\sum_{i=2}^{n}\frac{1}{i}\sum_{j=1}^{i-1}\frac{1}{j}\\
&=n!H_n+\sum_{1\le i\lt j\le n}\frac{n!}{ij}
\end{aligned}
\]
这样分母就可以全部抵消了,预处理调和级数前 \(n\) 项系数的前缀和与后缀和可以 \(\mathcal O(n)\) 求解。
源代码
/* Lucky_Glass */
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 1e7 + 10;
typedef long long llong;
int mod;
inline int reduce(llong key) {
return int((key %= mod) < 0 ? key + mod : key);
}
int pre[N], suf[N];
int main() {
freopen("cartesian.in", "r", stdin);
freopen("cartesian.out", "w", stdout);
int n; scanf("%d%d", &n, &mod);
pre[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);
int 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 = reduce(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);
return 0;
}
THE END
Thanks for reading!
最新文章
- SSRS 的简单使用(一)
- 在C#后端处理一些结果然传给前端Javascript或是jQuery
- dos常用命令
- ACM题目————二叉树最大宽度和高度
- LaTeX内容总结
- (转)Java操作Hbase进行建表、删表以及对数据进行增删改查,条件查询
- make fontconfig 时出现No package ‘libxml-2.0′ found的解决方法
- .NET批量大数据插入性能分析及比较
- 二、AspNet Core添加EF的基本方法(简略版):
- CSS变量variable
- Java的类C结构体的实现,以及对类的某一属性进行排序
- 《SQL CookBook 》笔记-第二章-查询结果排序
- 一分钟理解 HTTPS 到底解决了什么问题
- python之hashlib
- ES6快速入门(三)类与模块
- 原生ajax中get和post请求
- collectd+influxDB+Grafana搭建性能监控平台
- 多线程中实现ApplicationContextAware接口获取需要的bean,applicationContext.getBea未返回也未报错
- OCR技术(光学字符识别)
- MySQL C#连接ySQL保存当前时间,时分秒都是0,只有日期
热门文章
- 【学习笔记】C/C++ 设计模式 - 工厂模式(上)
- 真正“搞”懂HTTPS协议15之安全的定义
- 手把手教你为基于Netty的IM生成自签名SSL/TLS证书
- 零基础解读ChatGPT:对人类未来工作是威胁还是帮助?
- Atcoder题解:Arc156_c
- 一次k8s docker下.net程序的异常行为dump诊断
- mac sourceTree 每次操作提示需要密码
- redis 集群配置(从0到1)
- 野火STM32 ADC独立模式单通道采集实验意外
- idea插件连接数据库失败问题