zoukankan      html  css  js  c++  java
  • 「SOL」打扫笛卡尔cartesian (模拟赛)

    为什么会有人推得出来第三题想不出来签到题啊 (⊙_⊙)?

    题面

    有一棵有根树 (T)。从根节点出发,在点 (u) 时,设点 (u) 还有 (d) 个未访问过的儿子,则有 (frac1{d+1}) 的概率向上(深度较小的方向)走一步,有 (frac1{d+1}) 的概率走向一个未访问过的儿子。从根节点往上走则结束游走。

    (f(T)) 为这样游走到达的点的深度之和的期望。

    给定 (N)(Nle10^7)),对 ((1,2,dots,N)) 的所有排列 (P),建立小根的笛卡尔树 (T_P),求

    [sum_{P}f(T_p) ]

    答案对给定的正整数 (mod)(nlt modle2 imes10^9))取模,(mod) 不一定是质数。


    解析

    先分析在 (T) 上的游走方法。笛卡尔树是二叉树,若当前点有未访问的儿子,则:

    • 只有一个儿子时,有 (frac 12) 的概率会走向该儿子;
    • 有两个儿子时,有 (frac 13) 的概率第一次就走向该儿子,有 (frac 13 imesfrac 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),选出左子树的元素 (inom{n-1}{l})。利用期望的线性性,左子树的贡献为 (f_l) 乘上右子树的方案数,一个排列显然和一棵笛卡尔树一一对应,所以贡献即为 (f_l imes(n-l-1))。右子树同理,最后还要加上根的贡献,对于 (n!) 种笛卡尔树根的贡献都是 (1)

    [f_n=n!+frac 12sum_{l=0}^{n-1}inom{n-1}{l}Big((n-l-1)!f_l+l!f_{n-l-1}Big) ]

    先不管 (g_n),继续推导 (f_n) 的式子:

    [egin{aligned} f_n&=n!+sum_{l=0}^{n-1}inom{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!}=1+frac 1nsum_{l=0}^{n-1}frac{f_l}{l!} ]

    显然可以把 (frac{f_n}{n!}) 看成一个整体,发现转移式的主体是一个前缀和。记 (F_n)(frac {f_i}{i!})(ige1))的前缀和,则式子可以简化为:

    [F_n-F_{n-1}=1+frac 1nF_{n-1} o F_n=1+frac{n+1}{n}F_{n-1} ]

    (F_0=0),多次迭代过后可以得到 (F_n) 的通项。

    [F_n=sum_{i=2}^{n+1}frac{n+1}{i} ]

    有一个类似于调和级数前 ((n+1)) 项的东西,设调和级数前 (n) 项为 (H_n)

    [egin{align} F_n=(n+1)(H_n-1)& ag{1} end{align} ]

    现在回头看一看 (g_n),大致转移与 (f_n) 相同,但是根的贡献是 (f_n),也即 (siz_n) 的期望值(所以先推导 (f))。

    [egin{aligned} g_n&=f_n+frac12sum_{l=0}^{n-1}inom{n-1}{l}Big((n-l-1)!g_l+l!g_{n-l-1}Big)\ &=f_n+sum_{l=0}^{n-1}inom{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)) 代入。

    [egin{align} G_n-G_{n-1}&=1+frac 1n(F_{n-1}+G_{n-1}) otag\ &=H_n+frac 1nG_{n-1}& otag\ o G_n&=H_n+frac{n+1}{n}G_{n-1}& ag{2} end{align} ]

    ((2)) 进行迭代也可以得到 (G_n) 的通项公式:

    [G_n=sum_{i=1}^{n}frac{n+1}{i+1}H_i ]

    我们要算的答案是 (g_n=n!(G_n-G_{n-1})),由于 (mod) 不一定是质数,那还得继续推式子。

    [egin{aligned} 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_{1le ilt jle 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
    ", ans);
      return 0;
    }
    

    THE END

    Thanks for reading!

    霓虹中 错落影像
    满城声色褪去喧嚷
    废墟上 余碑文几行
    未铭记何谈淡忘

    ——《岁月成碑》By 乐正绫/Days

    > Link 岁月成碑 - 网易云

    欢迎转载٩(๑❛ᴗ❛๑)۶,请在转载文章末尾附上原博文网址~
  • 相关阅读:
    Microsoft Visual C++ 2015安装失败,提示设置失败,一个或多个问题导致了安装失败
    C# 下载url文件 WebClient、HttpWebRequest
    sqlite中插入单引号
    Advanced Installer 14.9 – WPF或winform应用程序打包成exe文件
    凤凰队历险记
    GUI如何设置默认字体 转载
    ubuntu切换清华源 安装gcc
    AttributeError: module ‘arviz’ has no attribute ‘geweke’
    解决ssh 连接报错 network error software caused connection abort 自动中断 转载
    VMWare安装64位CentOS7.6(截图多)
  • 原文地址:https://www.cnblogs.com/LuckyGlass-blog/p/14948351.html
Copyright © 2011-2022 走看看