LOJ#6495. 「雅礼集训 2018 Day1」树
题目描述
有一棵 n 个点的有根树,点编号为1至n,其中1号点为根,除 1号点外,i号点的父亲在 1至 i -1 内均匀随机。
定义一棵树的深度为所有节点到根路径上节点数的最大值,求这棵树的期望深度。
题解
一道披着期望外衣的计数题
考虑 F[i][j]为I个点期望深度J点的个数
然后就按计数题做呗
因为2号点的父亲一定是一号点
就讨论一下深度最深的点是在2号节点对应的子树中还是其他子树中
#include<bits/stdc++.h> #define LL long long using namespace std; inline LL read() { LL f = 1 , x = 0; char ch; do { ch = getchar(); if(ch=='-') f=-1; } while(ch<'0'||ch>'9'); do { x=(x<<3) + (x<<1) + ch - '0'; ch = getchar(); }while(ch>='0'&&ch<='9'); return f*x; } const int MAXN = 24 + 50; int n,p; long long C[MAXN][MAXN]; double dc[MAXN][MAXN]; long long dp1[MAXN][MAXN]; double dp2[MAXN][MAXN]; inline long long Pow(int a,int b) { long long res = 1 ,mul = a; while(b) { if(b & 1) { res *= mul; res %= p; } mul *= mul; mul %= p; b >>= 1; } return res; } inline double dfac(int x) { if(x == 1||x == 0) return 1.0; else return 1.0 * x * dfac(x-1); } inline long long fac(int x) { if(x == 1 ||x == 0) return 1; else return x * fac(x-1)%p; } int main() { n = read(),p = read(); for(int i=0;i<=n;i++) { C[i][0] = 1;dc[i][0] = 1; for(int j=1;j<=i;j++) { C[i][j] = (C[i-1][j] + C[i-1][j-1]) % p; dc[i][j] = dc[i-1][j] + dc[i-1][j-1]; } } dp1[1][1] = dp1[2][2] = dp2[1][1] = dp2[2][2] = 1; for(int i=3;i<=n;i++) { for(int j=2;j<=i;j++) { for(int k=1;k<=i-2;k++) { for(int dep=1;dep<=min(j-2,k);dep++) { dp1[i][j] = (dp1[i][j] + 1LL * dp1[k][dep] * dp1[i-k][j] % p * C[i-2][k-1] % p) % p; dp2[i][j] = dp2[i][j] + dp2[k][dep] * dp2[i-k][j] * dc[i-2][k-1]; } } for(int k=1;k<i;k++) { for(int dep=1;dep<=j;dep++) { dp1[i][j] = (dp1[i][j] + 1LL * dp1[k][j-1] * dp1[i-k][dep] % p * C[i-2][k-1] % p) % p; dp2[i][j] = (dp2[i][j] + dp2[k][j-1] * dp2[i-k][dep] * dc[i-2][k-1]); } } } } long long ans = 0; double dans = 0; for(int i=1;i<=n;i++) { ans = (ans + 1LL * i * dp1[n][i] % p) % p; dans = dans + i * dp2[n][i]; } printf("%.0lf ",round(dans/dfac(n-1))); printf("%lld ",1LL * ans * Pow(fac(n-1),p-2) % p); return 0; }