這個故事發生在好久之前,在$IcePrincess\text{_}1968$和$IcePrince\text{_}1968$都還在上幼兒園的時候。
$IcePrince\text{_}1968$最近迷上了一種玩具,這種玩具中有兩種零件:圓球和棍子。棍子的兩頭能夠插在兩個圓球上的各一個空洞中,從而將兩個圓球鏈接起來。爲了保證玩具的娛樂性,任意一個圓球上的空洞個數老是多於玩具套裝中的棍子數。你能夠認爲圓球是沒有體積的,全部棍子的長度均爲$1$。
$IcePrince\text{_}1968$喜歡這樣玩這種玩具:他先摸出玩具袋裏的一個圓球放在地上,而後重複下面的操做$n-1$次:每次從袋中取出一個圓球和一根棍子,而後等機率的從地上的圓球中選擇一個,將該圓球和選擇的圓球用棍子連起來,使得新的圓球在選中圓球的正上方。
$IcePrince\text{_}1968$對本身搭出的藝術品很滿意,便決定把這個物品送給$IcePrincess\text{_}1968$做爲生日禮物。然而生日禮物是須要包裝的,由於默認圓球沒有體積,因此$IcePrince\text{_}1968$不用考慮包裝盒的長和寬,可是包裝盒的高是須要肯定的,這裏咱們假設$IcePrince\text{_}1968$是一個很是節儉的孩子,因此包裝盒的高老是等於藝術品的高度。$IcePrince\text{_}1968$想知道本身須要的包裝盒的高的指望對質數$p$取模後的值,但他還在上幼兒園,怎麼會算呢,因而就請你來幫助他。c++
輸入文件名爲$toy.in$。
輸入數據僅一行,包含兩個正整數$n,p$,表示最終的藝術品中圓球的個數和模數$p$。數組
輸出文件名爲$toy.out$。
輸入文件僅一行,一個正整數,表示包裝盒的高的指望對質數$p$取模後的值。spa
樣例輸入:blog
3 998244353it
樣例輸出:class
499122178im
樣例解釋:數據
三個圓球組成的藝術品,高度只多是$1$或者$2$,因此高度的指望是$1.5$,在模$998244353$下的指望是$499122178$。db
數據範圍:img
對於$30\%$的數據,知足$n\leqslant 10,p\leqslant 1,000,007$;
對於$50\%$的數據,知足$n\leqslant 20$;
對於$70\%$的數據,知足$n\leqslant 50$;
對於$100\%$的數據,知足$n\leqslant 200,p\leqslant 1,000,000,007$,$p$是質數。
超級神奇的$DP$,先做出以下定義:
$\alpha.$設$dp[i][j]$表示$i$個點的森林,有$j$個點在第一棵樹的機率。
$\beta.$設$f[i][j]$表示有$i$個點的樹,深度不超過$j$的機率。
$\gamma.$設$g[i][j]$表示有$i$個點的森林,深度不超過$j$的機率。
那麼,先考慮如何求出$dp$數組,有:
$$dp[i][j]=dp[i-1][j-1]\times\frac{j-1}{i}+dp[i-1][j]\times\frac{i-j}{i}$$
初始化$dp[1][1]=1$。
解釋一下,式子的前一半是將新加入的點放入了第一棵樹,那麼它能夠接到$(j-1)$個點上, 後一半是將新加入的這個點放入了除第一棵樹外的其它樹上(也能夠新建一棵樹),分母是$i$而不是$(i-1)$的是因爲這個點能夠新建一棵樹,也就是至關於跟誰也沒有相接。
接着考慮一個式子:
$$f[i][j]=g[i-1][j-1]$$
化個圖你就理解了$\downarrow$
$$\Downarrow$$
也就是說,咱們加了一個點,讓這棵森林中的全部樹都連到了這個節點上。
再來考慮如何求出$g$數組:
$$g[i][j]=\sum \limits_{k=1}^if[k][i]\times g[i-1][j]\times dp[i][k]$$
這至關因而在$i$個點中選取了$k$個點組成第一棵樹,剩下$k$個點仍是一個森林,$dp[i][k]$至關因而係數,也就是這第一棵樹的形態數。
最後,由於$f$數組的意義是$f[i][j]$有$i$個點的樹,深度不超過$j$的機率;因此咱們須要知道深度剛好爲$j$的機率,即爲$f[n][j]-f[n][j-1]$。
將每個深度的機率乘上其深度再加和即爲答案。
時間複雜度:$\Theta(n^3)$。
指望得分:$100$分。
實際得分:$100$分。
#include<bits/stdc++.h>
using namespace std;
int n,p;
long long inv[201];
long long dp[201][201],f[201][201],g[201][201];
long long ans;
long long qpow(long long x,long long y)
{
long long res=1;
while(y)
{
if(y&1)res=res*x%p;
x=x*x%p;
y>>=1;
}
return res;
}
int main()
{
scanf("%d%d",&n,&p);
dp[1][1]=f[1][0]=1;
for(int i=1;i<=n;i++)inv[i]=qpow(i,p-2);
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++)
dp[i][j]=(dp[i-1][j-1]*(j-1)%p+dp[i-1][j]*(i-j)%p)*inv[i]%p;
for(int i=0;i<=n;i++)g[0][i]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=n;j++)
{
if(j)f[i][j]=g[i-1][j-1];
for(int k=1;k<=i;k++)g[i][j]=(g[i][j]+f[k][j]*g[i-k][j]%p*dp[i][k]%p)%p;
}
for(int i=1;i<=n;i++)ans=(ans+(f[n][i]-f[n][i-1]+p)%p*i%p)%p;
printf("%lld",ans);
return 0;
}
rp++