P4492 [HAOI2018]蘋果樹
阿新 • • 發佈:2018-11-13
除了神仙啥都不想說了orz->這裡
首先生成二叉樹的時候,第一個點有\(1\)種選法,第二個點有\(2\)種選法...第\(n\)個點有\(n\)種選法,於是樹的形態共有\(n!\)種,需要求它們總共的點對距離和
發現按點來考慮太麻煩了,我們按邊來考慮貢獻,對\(i\)的父親邊來說,有\(sz_i(n-sz_i)\)個點對會經過這一條邊,所以這一條邊對答案就有這麼多的貢獻
於是考慮一下\(O(n^2)\)的列舉,設\(sz_i\)為子樹的大小,\(i\)為當前點,那麼這棵子樹的形態有\(sz_i!\)種,子樹的編號有\(C_{n-i}^{sz_i-1}\)種(生成\(i\)之後從剩下的點中選出\(sz_i-1\)
然後考慮子樹外的方案數,生成\(i\)之前共有\(i!\)種方法,而生成\(i\)之後的點不能放到\(i\)的子樹中,於是後面的點有\((i+1-2),(i+2-2),...(n-sz_i+1-2)\)種方法(因為放到\(i\)的子樹中的點並不會影響外面的點的方案數),乘起來化簡一下就是\(i(i-1)(n-sz_i-1)!\)種方法
於是最後的答案就是\[ans=\sum_{i=2}^{n}\sum_{j=1}^{n-i+1}j(n-j)j!C_{n-i}^{j-1}i(i-1)(n-j-1)!\]
//minamoto #include<bits/stdc++.h> #define ll long long using namespace std; const int N=2005; int n;ll mod,dp[N][N],C[N][N],fac[N],res; int main(){ // freopen("testdata.in","r",stdin); scanf("%d%lld",&n,&mod),fac[0]=1; for(int i=0;i<=n;++i)C[i][i]=C[0][i]=1; for(int i=0;i<=n;++i)for(int j=1;j<n;++j)C[j][i]=(C[j-1][i-1]+C[j][i-1])%mod; for(int i=1;i<=n;++i)fac[i]=fac[i-1]*i%mod;dp[1][1]=1; // for(int i=2;i<=n;++i)for(int j=1;j<=i;++j)dp[i][j]=fac[i-2]*j%mod*(j-1)%mod; // for(int i=2;i<=n;++i)for(int j=1;j<=n-i+1;++j) // (res+=fac[j]*C[j-1][n-i]%mod*j*(n-j)%mod*dp[n-j+1][i])%=mod; // 下面也可以這樣打表預處理一下再算 for(int i=2;i<=n;++i)for(int j=1;j<=n-i+1;++j) (res+=fac[j]*C[j-1][n-i]%mod*j*(n-j)%mod*fac[n-j-1]%mod*i%mod*(i-1)%mod)%=mod; printf("%lld\n",res);return 0; }