「雅礼集训 2018 Day1」树

「雅礼集训 2018 Day1」树

传送门

Loj

题解

考虑设\(f_{i,j}\)表示\(i\)个点的树,深度为\(j\)的方案数.

转移考虑所有树的\(1,2\)节点一定是同一种结构,直接枚举\(2\)对应子树的大小然后合并即可.

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
typedef pair<int,int> pii;
#define mp make_pair
inline int gi()
{
	int f=1,sum=0;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=50;
int f[N][N],n,Mod,c[N][N];
int ans[N]={0,1,2,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6};
int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=1ll*ret*a%Mod;b>>=1;a=1ll*a*a%Mod;}return ret;}
int main()
{
	n=gi();Mod=gi();
	printf("%d\n",ans[n]);
	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]+c[i-1][j-1])%Mod;
	}
	f[1][1]=1;
	for(int i=2;i<=n;i++)
		for(int j=2;j<=i;j++)
			for(int x=1;x<i;x++)
			{
				for(int y=1;y<j-1;y++)f[i][j]=(f[i][j]+1ll*f[x][y]*f[i-x][j]%Mod*c[i-2][x-1]%Mod)%Mod;
				for(int y=1;y<=j;y++)f[i][j]=(f[i][j]+1ll*f[i-x][y]*f[x][j-1]%Mod*c[i-2][x-1]%Mod)%Mod;
			}
	int res=0;
	for(int i=1;i<=n;i++)res=(res+1ll*f[n][i]*i%Mod)%Mod;
	for(int i=1;i<n;i++)res=1ll*res*qpow(i,Mod-2)%Mod;
	printf("%d\n",res);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/fexuile/p/12893787.html