zoukankan      html  css  js  c++  java
  • 长沙理工大学第十二届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]$

  • 相关阅读:
    [React Testing] Intro to Shallow Rendering
    人物-IT-马化腾:马化腾
    人物-IT-雷军:雷军
    Less:Less(CSS预处理语言)
    文学-谚语-英文谚语:英文谚语
    文明-墓-太阳墓:太阳墓
    地理-撒哈拉之眼:撒哈拉之眼
    生物-海底人:海底人
    地理-蓝洞:蓝洞
    文明-根达亚文明:根达亚文明
  • 原文地址:https://www.cnblogs.com/uid001/p/10925416.html
Copyright © 2011-2022 走看看