[HAOI2018] 蘋果樹

顯然,隨機產生的n個節點二叉樹共有n!中結構,且出現每種結構的機率相同,所以之需求全部方案的不方便度之和便可。c++

讓邊的編號爲兒子節點的編號。考慮邊i(i∈[2,n])在全部狀況下產生的貢獻?(很重要的方法算法

枚舉點i的子樹大小t(t∈[1,n-i+1]),對應的每張方案邊i都有t(n-t)的貢獻。spa

計算點i的子樹大小t的方案數?造成邊的方案i!, 子樹的方案(有t-1個未知編號)t!*C(n-i,t-1),還有n-i+1-t個點依次在有i-1個空分支的基礎上生長,這部分的方案爲i-1的n-i+1-t上階乘冪,即(n-t-1)!/(i-2)!code

綜上所述,答案爲sum_{i∈[2,n]} sum_{t∈[1,n-i+1]} i!t(n-t)t!C(n-i,t-1)*(n-t-1)!/(i-1)!,O(n^2)算法躍然鍵上it

彷佛有的數不必定有逆?class

#include <bits/stdc++.h>
#define ll long long 
using namespace std;

const int N=2e3+10;

int n,P;
int fc[N],c[N][N],d[N][N];

int main() {
    scanf("%d%d",&n,&P);
    fc[0]=c[0][0]=1;
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=i; ++j) 
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
        c[i][0]=1; fc[i]=1LL*fc[i-1]*i%P;
    }
    for(int i=1; i<n; ++i) {
        d[i][0]=1;
        for(int j=1; j<=n; ++j) 
            d[i][j]=1LL*d[i][j-1]*(i+j-1)%P;
    }
    int ans=0;
    for(int i=2; i<=n; ++i) {
        for(int t=1; t<=n-i+1; ++t) 
            ans=(ans+1LL*fc[i]*t%P*(n-t)%P*fc[t]%P*c[n-i][t-1]%P*d[i-1][n-i+1-t]%P)%P;
    }
    printf("%d\n",ans);
    return 0;
}
相關文章
相關標籤/搜索