[洛谷P4492] HAOI2018 蘋果樹
問題描述
小 C 在自己家的花園裡種了一棵蘋果樹, 樹上每個結點都有恰好兩個分支. 經過細心的觀察, 小 C 發現每一天這棵樹都會生長出一個新的結點.
第一天的時候, 果樹會長出一個根結點, 以後每一天, 果樹會隨機選擇一個當前樹中沒有長出過結點 的分支, 然後在這個分支上長出一個新結點, 新結點與分支所屬的結點之間連線上一條邊.
小 C 定義一棵果樹的不便度為樹上兩兩結點之間的距離之和, 兩個結點之間 的距離定義為從一個點走到另一個點的路徑經過的邊數.
現在他非常好奇, 如果 N 天之後小 G 來他家摘蘋果, 這個不便度的期望 E 是多少. 但是小 C 討厭分數, 所以他只想知道 \(E \times N !\)
輸入格式
從標準輸入中讀入資料. 一行兩個整數 \(N, P\) .
輸出格式
輸出到標準輸出中. 輸出一個整數表示答案.
樣例輸入
3 610745795
樣例輸出
24
資料範圍
\(N \le 2000,P\le 10^9+7\)
解析
老套路題了。
不難發現,第 N 天的樹上一定有 N+1 個分支可以長結點。因此,大小為 N 的滿足要求的樹有 N! 中方法。
直接統計十分複雜,我們考慮計算每條邊的貢獻。設當前列舉的是節點 \(i\) 的父邊,其子樹大小為 \(j\) 。那麼,在確定樹的形態的情況下,這條邊會被經過 \(j(n-j)\) 次。
接下來分別考慮子樹和子樹外的形態。對於子樹,由之前的結論,有 \(j!\) 種不同的形態。而考慮編號的問題,子樹內的編號一定都大於 \(i\) 。所以總方案數為 \(j!C_{n-i}^{j-1}\) 。對於子樹外,首先在前 \(i\) 天時就有 \(i!\) 中形態。在第 \(i\) 天之後,除了欽定的在子樹內的點以外,其餘的每一個點都可以放在子樹外的一個分支上,依次有 \(i+1-2...n-j-1\) 種方案(因為點放在子樹內導致的分支增加對子樹外沒有影響,畢竟不能放上去)。綜上,總貢獻為
\[j(n-j)\times j!C_{n-i}^{j-1}\times i(i-1)(n-j-1)! \]
列舉 \(i\) 和 \(j\) 即可。
程式碼
#include <iostream>
#include <cstdio>
#define int long long
#define N 2002
using namespace std;
int n,mod,i,j,c[N][N],fac[N],ans;
signed main()
{
scanf("%lld%lld",&n,&mod);
for(i=fac[0]=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
c[0][0]=1;
for(i=1;i<=n;i++){
c[i][0]=1;
for(j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
for(i=1;i<=n;i++){
for(j=1;j<=n-i+1;j++){
int tmp=fac[j]*c[n-i][j-1]%mod*i%mod*(i-1)%mod*fac[n-j-1]%mod*j%mod*(n-j)%mod;
ans=(ans+tmp)%mod;
}
}
printf("%lld\n",ans);
return 0;
}