ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[HAOI2018]苹果树

2019-03-04 09:39:14  阅读:227  来源: 互联网

标签:sz 结点 子树 个点 方案 样例 苹果树 HAOI2018


题目描述

小 C 在自己家的花园里种了一棵苹果树, 树上每个结点都有恰好两个分支. 经过细心的观察, 小 C 发现每一天这棵树都会生长出一个新的结点.

第一天的时候, 果树会长出一个根结点, 以后每一天, 果树会随机选择一个当前树中没有长出过结点 的分支, 然后在这个分支上长出一个新结点, 新结点与分支所属的结点之间连接上一条边.

小 C 定义一棵果树的不便度为树上两两结点之间的距离之和, 两个结点之间 的距离定义为从一个点走到另一个点的路径经过的边数.

现在他非常好奇, 如果 NN 天之后小 G 来他家摘苹果, 这个不便度的期望 EE 是多少. 但是小 C 讨厌分数, 所以他只想知道 E \times N !E×N! 对 PP 取模的结果, 可以证明这是一个整数.

输入输出格式

输入格式:

从标准输入中读入数据. 一行两个整数 NN, PP .

输出格式:

输出到标准输出中. 输出一个整数表示答案.

输入输出样例

输入样例#1:

3 610745795

输出样例#1:

24

输入样例#2:

305 1000000007

输出样例#2:

865018107


题解

挺难的一道计数题,对着题解理解半天才大致搞懂
首先观察题目可以发现:每棵二叉树对应了唯一的中序遍历
所以当我们要放第\(i\)个点的时候就有\(i\)种方案了
计算点对间的距离肥肠困难,所以我们只考虑每条边对答案的贡献
显然一条边\((u,v)\)的贡献就是\(size[v]*(n-size[v])\),也就是一条边的一端的子树中走到另一端的子树中的方案数
有了每条边对一种方案的贡献,我们就可以考虑去计算每条边的方案数了
我们发现每条边出现不同的贡献的原因就是这条边的一端的子树大小不同
所以就可以考虑枚举这条边的一端的子树的大小来计算每条边的贡献
那么现在只需要解决有多少种方案满足点\(i\)的子树大小为\(sz\)即可
考虑将子树内和子树外的方案数分开计算

先考虑\(i\)的子树内的情况:

如果没有标号的话点i就有\(sz!\)种不同的子树
显然点\(i\)的子树内点的标号一定比\(i\)要大,且\(i\)这个标号一定要选
所以可选取的标号的方案数就是\(C(n - i , sz)\)
所以子树这一部分的方案数是\(C(n - i , sz) * sz!\)

再考虑\(i\)的子树外的情况

我们可以这么考虑,由于我们已经弄了一个\(i\)及\(i\)的子树了
所以我们就把点\(i\)及其子树想成一个大的点且这个点的左右儿子都不能选
这样我们要处理的点的数量就是\(n - sz + 1\)
由于子树内已经选完\(sz-1\)个点了,所以剩下的\(n - sz + 1\)个点是确定的
前\(i\)个点没有限制,所以方案数就是\(i!\)
然后对于后面的某一点\(i+k(i + k <= n - sz + 1)\),由于点\(i\)的左右子树都不能选了,所以方案数就是\(i + k - 2\)
这样一来后面的点的方案数就是\(\prod_{k=1}^{i+k<=n-sz+1}{i+k-2}\)
所以子树外这一部分的方案数就是\(i!\prod_{k=1}^{i+k<=n-sz+1}{i+k-2}=(i-1)*i*(n-sz-1)!\)

所以总的方案数就是\(C(n - i , sz) * sz!*(i-1)*i*(n-sz-1)!\)
然后再乘上这条边的贡献\(sz*(n-sz)\)就是答案了

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
const int M = 2005 ;
using namespace std ;

int n , mod , ans , C[M][M] , fac[M] ;

int main() {
    scanf("%d%d",&n,&mod) ;
    C[0][0] = 1 ;
    for(int i = 1 ; i <= n ; i ++) {
        C[i][0] = 1 ;
        for(int j = 1 ; j <= i ; j ++)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod ;
    }
    fac[0] = 1 ;
    for(int i = 1 ; i <= n ; i ++) fac[i] = 1LL * fac[i - 1] * i % mod ;
    for(int i = 2 ; i <= n ; i ++)
        for(int sz = 1 ; sz <= n - i + 1 ; sz ++)
            ans = (ans + 1LL * sz * (n - sz) % mod * C[n - i][sz - 1] % mod * fac[sz] % mod * (i - 1) % mod * i % mod * fac[n - sz - 1] % mod) % mod ;
    printf("%d\n",ans) ;
    return 0 ;
}

标签:sz,结点,子树,个点,方案,样例,苹果树,HAOI2018
来源: https://www.cnblogs.com/beretty/p/10468927.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有