ICode9

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

CF724F Uniformly Branched Trees

2021-06-26 14:02:03  阅读:162  来源: 互联网

标签:CF724F 方案 ch frac 重心 int Uniformly 子树 Branched


tag:重心,dp,组合计数


晕呼呼地计数...

题意

求 \(n\) 个点的不同的树的个数(同构视为一种,无标号),使得每个点的度数为 \(1\) 或 \(d\)。

\(n\le1000, 2\le d\le10\)


题解

无标号树同构问题一般想到找重心,把重心作为根,这里先假设重心唯一(\(n\) 为奇数)。

设一个树 \(dp\),\(f_{i,j,k}\) 表示当前子树一共有 \(i\) 个节点,当前根有 \(j\) 个儿子,每个儿子的子树大小都不超过 \(k\)。那么答案就是 \(f_{n,d,\left\lfloor\frac n2\right\rfloor}\)。


首先若所有子树都小于 \(k\),递归到 \(f_{i,j,k-1}\)。

第二种情况枚举 \(p\) 个子树大小为 \(k\),递归到 \(f_{i-pk,j-p,k-1}\),转移系数为 \(\binom{f_{k,d-1,k-1}+p-1}p\)。可以把每个子树理解为一个球,方案理解为一个盒子,因为子树之间没有顺序,所以问题对应为“将相同的球放入不同的盒子里,可以为空”的方案数。


然后考虑 \(n\) 为偶数。这时可能会有 \(2\) 个重心,会多算一些方案。比如重心 \(1\) 选择方案 \(a\),重心 \(2\) 选择方案 \(b\);和重心 \(1\) 选择方案 \(b\),重心 \(2\) 选择方案 \(a\),构成的是同一棵树。但是用之前的方法计算时,会把一个重心当作另一个重心的儿子,所以上述的两种方案会被视为两种不同的方案。所以还要减去 \(\binom{f_{\frac n2,d-1,\frac n2-1}}2\)。


注意一下特判 \(n\le2\)。

#include<bits/stdc++.h>
using namespace std;
 
template<typename T>
inline void Read(T &n){
    char ch; bool flag=false;
    while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
    for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
    if(flag)n=-n;
}

enum{
	MAXN = 1005,
	D = 15
};

int n, d, MOD, f[D][MAXN][MAXN];

inline int dec(int a, int b){
	a -= b;
	if(a<0) a += MOD;
	return a;
}

inline int ksm(int base, int k=MOD-2){
	int res=1;
	while(k){
		if(k&1)
			res = 1ll*res*base%MOD;
		base = 1ll*base*base%MOD;
		k >>= 1;
	}
	return res;
}

int inv[D];
inline void prework(int n){
	for(register int i=1; i<=n; i++) inv[i] = ksm(i);
}

inline int cn2(int n){return 1ll*n*(n-1)/2%MOD;}

int dp(int n, int d, int k){
	if(n==1 and !d) return 1;
	if(k==1) return d+1==n;
	if(~f[d][n][k]) return f[d][n][k];
	int &res = f[d][n][k] = 0;
	res = dp(n,d,k-1);
	int tmp = dp(k,::d-1,k-1), kkk = tmp;
	for(register int i=1; i*k<n and i<=d; i++)
		res = (res+1ll*dp(n-i*k,d-i,k-1)*kkk)%MOD,
		kkk = 1ll*kkk*(tmp+i)%MOD*inv[i+1]%MOD;
	return res;
}

int main(){
	Read(n); Read(d); Read(MOD);
	memset(f,-1,sizeof f);
	prework(d);
	if(n<=2) return puts("1"), 0;
	if(n&1) printf("%d\n",dp(n,d,n/2));
	else printf("%d\n",dec(dp(n,d,n/2),cn2(dp(n/2,d-1,n/2-1))));
	return 0;
}

标签:CF724F,方案,ch,frac,重心,int,Uniformly,子树,Branched
来源: https://www.cnblogs.com/oisdoaiu/p/14934095.html

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

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

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

ICode9版权所有