【题目】
题目描述:
这个故事发生在很久以前,在 IcePrincess_1968 和 IcePrince_1968 都还在上幼儿园的时候。
IcePrince_1968 最近迷上了一种玩具,这种玩具中有两种零件:圆球和棍子。棍子的两头可以插在两个圆球上的各一个空洞中,从而将两个圆球连接起来。为了保证玩具的娱乐性,任意一个圆球上的空洞个数总是多于玩具套装中的棍子数。你可以认为圆球是没有体积的,所有棍子的长度均为 。
IcePrince_1968 喜欢这样玩这种玩具:他先摸出玩具袋里的一个圆球放在地上,然后重复下面的操作 次:每次从袋中取出一个圆球和一根棍子,然后等概率的从地上的圆球中选择一个,将该圆球和选择的圆球用棍子连起来,使得新的圆球在选中圆球的正上方。
IcePrince_1968 对自己搭出的艺术品很满意,便决定把这个物品送给 IcePrincess_1968 作为生日礼物。然而生日礼物是需要包装的,因为默认圆球没有体积,所以 IcePrince_1968 不用考虑包装盒的长和宽,但是包装盒的高是需要确定的,这里我们假设 IcePrince_1968 是一个非常节俭的孩子,所以包装盒的高总是等于艺术品的高度。IcePrince_1968 想知道自己需要的包装盒的高的期望对质数 取模后的值,但他还在上幼儿园,怎么会算呢,于是就请你来帮助他。
输入格式:
输入数据仅一行,包含两个正整数 ,表示最终的艺术品中圆球的个数和模数 。
输出格式:
输入文件仅一行,一个正整数,表示包装盒的高的期望对质数 取模后的值。
样例数据:
输入
3 998244353
输出
499122178
提示:
【输入输出样例 解释】
三个圆球组成的艺术品,高度只可能是 或者 ,所以高度的期望是 ,在模 下的期望是 。
【数据范围】
对于 的数据,满足 , ;
对于 的数据,满足 ;
对于 的数据,满足 ;
对于 的数据,满足 , , 是质数。
【分析】
这道题我不是很会,先放上题解吧。
显然我们可以把最后做出来的玩具当成一棵树。
定义 为有 个点的树,深度不超过 层的概率, 为有 个点的森林,深度不超过 层的概率。
还有一个要预处理的:设 表示对于有 个点的森林,有 个点在第一个子树内的概率。
那么预处理的转移方程就是:
然后又因为 可以从 直接转移过来,就是:
最后的答案就是
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 205
using namespace std;
int n,p;
int dp[N][N],f[N][N],g[N][N],inv[N];
signed main()
{
int i,j,k,ans=0;
scanf("%d%d",&n,&p);
inv[0]=inv[1]=1,dp[1][1]=1;
for(i=2;i<=n;++i) inv[i]=1ll*(p-p/i)*inv[p%i]%p;
for(i=2;i<=n;++i)
for(j=1;j<=n;++j)
dp[i][j]=(1ll*dp[i-1][j-1]*(j-1)%p*inv[i]%p+1ll*dp[i-1][j]*(i-j)%p*inv[i]%p)%p;
for(i=0;i<=n;++i) g[0][i]=1;
for(i=1;i<=n;++i)
{
for(j=0;j<=n;++j)
{
if(j) f[i][j]=g[i-1][j-1];
else if(i==1) f[i][j]=1;
for(k=1;k<=i;++k)
g[i][j]=(g[i][j]+1ll*f[k][j]*g[i-k][j]%p*dp[i][k]%p)%p;
}
}
for(i=1;i<=n;++i)
ans=(ans+1ll*(f[n][i]-f[n][i-1]+p)%p*i%p)%p;
printf("%d",ans);
return 0;
}