• 长沙理工大学第十二届ACM大赛-重现赛 大家一起来数二叉树吧 (组合计数)


    大意: 求n结点m叶子二叉树个数.

    直接暴力, $dp[i][j][k][l]$表示第$i$层共$j$节点, 共$k$叶子, 第$i$层有$l$个叶子的方案数, 然后暴力枚举第$i$层出度为1和出度为2的个数来转移.

    复杂度虽然看上去是$O(n^6)$, 但实际上去掉多余状态后只有1178917, 可以通过.

    #include <iostream>
    #include <cstdio>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    using namespace std;
    typedef long long ll;
    const int P = 1e9+7, P2 = 998244353, INF = 0x3f3f3f3f;
    const int N = 55;
    int n, m;
    int dp[N][N][N][N];
    int f[N][N];
    int fac[N], ifac[N], pow2[N];
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    
    int main() {
    	fac[0]=ifac[0]=pow2[0]=1;
    	REP(i,1,50) fac[i]=(ll)fac[i-1]*i%P,ifac[i]=inv(fac[i]),pow2[i]=pow2[i-1]*2%P;
    	dp[1][1][1][1] = 1;
    	REP(i,1,50) REP(j,i,50) REP(k,1,j) REP(l,1,k) if (dp[i][j][k][l]) {
    		REP(ii,0,l) { 
    			int t = min({l-ii,(50-ii-j)/2,50-k});
    			REP(jj,0,t) {
    				int c = (ll)dp[i][j][k][l]*fac[l]%P*ifac[ii]%P*ifac[jj]%P*ifac[l-ii-jj]%P*pow2[ii]%P;
    				(dp[i+1][j+ii+2*jj][k+jj][ii+2*jj]+=c)%=P;
    			}
    		}
    		(f[j][k] += dp[i][j][k][l]) %= P;
    	}
    	for (int n,m; ~scanf("%d%d", &n, &m); ) printf("%d
    ", f[n][m]);
    }
    

    看了其他人题解后发现可以直接$O(n^4)$的$dp$.

    记$dp[i][j]$为$i$节点, $j$叶子的方案数, 枚举根节点左右子树的叶子数$x,y$, 就有

    $dp[i][j]=sum dp[x][y]dp[i-1-x][y]$

  • 相关阅读:
    不同操作系统的宏定义区分
    WINDOWS下VS编译opencv并加载自定义模块
    基于模板匹配的马赛克检验
    [转]C++模板详解
    [Linux命令]Unix/Linux信号量的使用
    [C/C++基础]读写文件
    [Linux命令]查看Linux系统相关命令
    【Linux命令】查找命令
    【QT相关】文件、目录基础操作
    【MFC相关】图片显示
  • 原文地址:https://www.cnblogs.com/uid001/p/10925416.html
Copyright © 2020-2023  润新知