烷基计数&烷烃计数(n^2算法)

烷基计数问题

 求每个节点的儿子不超过三个,且大小为$n$的有根树的数量。$1 \leq N \leq 2000$

 设$f[i][j]$为总共$i$个节点,根节点度数为$j$的方案数。

 考虑从$1到N-1$枚举一个当前最大的子树大小$sz$和选的个数$k$,把他接在原来的部分方案上。

 于是就有

  $f[i][j]+=f[i-sz*k][j-k]*H^{k}_{\sum_{m=0}^{3} f[sz][m]}$

 其中H为可重复的组合数,即$H^{m}_{n}$代表$n$个选$m$个可重复选的方案数,因为需要考虑子树的同构。

 满足

  $H^{m}_{n}=C^{m}_{m+n-1}=\frac{(m+n-1)!}{m!(n-1)!}=\frac{1}{m!}\prod_{t=n}^{m+n-1} t$

 证明见文末。

  倒着枚举点的个数不会算重。

  最后答案即是$\sum_{i=0}^{3}f[N][i]$.

ll H(int a,int b){
    if(b==0) return 1;
    if(b==1) return a;
    if(b==2) return (ll)ny(2)*(a+1)%mod*a%mod;
    if(b==3) return (ll)ny(6)*(a+1)%mod*(a+2)%mod*a%mod;
}
int MAIN(){
    cin>>N;
    f[1][0]=1;
    for(int sz=1;sz<N;sz++){
        for(int i=N;i;i--){
           for(int j=1;j<=3&&j<i;j++){
               for(int k=1;k*sz+1<=i&&k<=j;k++){
                   int s=0;
                   for(int p=0;p<=3;p++) s=((ll)s+f[sz][p])%mod;
                   f[i][j]=((ll)f[i][j]+f[i-sz*k][j-k]*H(s,k)%mod)%mod;
               }
           }
       } 
    }
    ll ans=0;
    for(int i=0;i<=3;i++) ans+=f[N][i];
    cout<<ans%mod<<endl;
    return 0;
}

烷烃计数问题

 求每个节点的度数不超过四,且大小为$n$的无根树的数目。$1 \leq n \leq 2000$

 考虑将所有无根树的一个重心作为根(显然重心只有一或二个),形成有根树。

 这样做一定会满足每棵子树大小不超过$\frac{n}{2}$。

 这时需要修改$f[i][j]$的定义,即总共$i$个节点,根的度数为$j$且满足子树大小小于$\frac {n+1}{2}$的方案数。

 计算时sz必须满足$sz < \frac {n+1}{2}$

 为什么是$\frac {n+1}{2}$?

 分类讨论一下:

 当重心只有一个时:此时$f[n]$最大子树大小为$\frac {n-1}{2}$

 当重心有两个时:此时$f[\frac {n}{2}]$的所有情况都被计算了。

 所以这样是刚好把条件全部满足的。

 接下来统计答案:

 当重心只有一个时,答案为$\sum_{i=0}^{4} f[n][i]$.

 当重心有两个时,此时n一定是偶数,两个重心相邻且子树大小均为$\frac{n}{2}$(重心的基本性质)。

 所以答案需要额外加上$H^{2}_{\sum^{3}_{i=0}{f[\frac {n}{2}][i]}}$

ll H(int a,int b){
    if(b==0) return 1;
    if(b==1) return a;
    if(b==2) return (ll)ny(2)*(a+1)%mod*a%mod;
    if(b==3) return (ll)ny(6)*(a+1)%mod*(a+2)%mod*a%mod;
    if(b==4) return (ll)ny(24)*(a+1)%mod*(a+2)%mod*(a+3)%mod*a%mod;
}
int MAIN(){
    cin>>N;
    f[1][0]=1;
    for(int sz=1;sz<(N+1)/2;sz++){
        for(int i=N;i;i--){
            for(int j=1;j<=4&&j<i;j++){
               for(int k=1;k*sz+1<=i&&k<=j;k++){
                   int s=0;
                   for(int p=0;p<=3;p++) s=((ll)s+f[sz][p])%mod;
                   f[i][j]=((ll)f[i][j]+f[i-sz*k][j-k]*H(s,k)%mod)%mod;
               }
           }
       } 
    }
    ll ans=0;
    for(int i=0;i<=4;i++) ans+=f[N][i];
    if(N%2==0){
        int ret=0;
        for(int i=0;i<=3;i++) ret=(ret+f[N>>1][i])%mod;
        ans+=H(ret,2);
    }
    cout<<ans%mod<<endl;
    return 0;
}

 

证明:  $H^{m}_{n}=C^{m}_{m+n-1}$

不妨设要在长度为$n$的排列中可重复地选择$m$项,成为数列{$x$}。

 不妨设{$x$}满足$x_{i-1} \leq x_i$

 令$T_i = x_i+i-1$

 则有$T_{i-1}<T_i$且$T_i \in [1,n+m-1]$

 所以相当于在$[1,n+m-1]$中选择不重复的$m$项构成$T_i$.

 于是即证$H^{m}_{n}=C^{m}_{m+n-1}$.

posted @ 2022-05-23 11:06  xxqz  阅读(213)  评论(0编辑  收藏  举报