Codeforces 830D Singer House 动态规划
原文链接https://www.cnblogs.com/zhouzhendong/p/CF830D.html
题解
考虑用 dp[i][j] 表示深度为 i 的树里,有 j 条路径的方案数。分四种情况转移即可:
枚举 j,k ,我们来算一下 dp[i−1][j] 和 dp[i−1][k] 对 dp[i] 的贡献。
设 tmp=dp[i−1][j]×dp[i−1][k] ,
1. 不合并任何路径。dp[i][j+k]+=tmp
2. 不合并,并加入当前根节点单独组成路径。dp[i][j+k+1]+=tmp
3. 合并根和任意一条路径。dp[i][j+k]+=tmp×2(j+k)
4. 合并根和任意两条路径。dp[i][j+k-1]+= tmp \times 2\binom{j+k}{2}
由于当 j>n 的时候,dp[i][j] 对于最终答案一定没有贡献(这么多路径不可能合并成一条),所以 dp 状态第二维的上界是 n 。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <bits/stdc++.h> using namespace std; typedef long long LL; LL read(){ LL x=0,f=1; char ch= getchar (); while (! isdigit (ch)&&ch!= '-' ) ch= getchar (); if (ch== '-' ) f=0,ch= getchar (); while ( isdigit (ch)) x=(x<<1)+(x<<3)+(ch^48),ch= getchar (); return f?x:-x; } const int N=405,mod=1e9+7; int n; int Inv[N],Fac[N]; int Pow( int x, int y){ int ans=1; for (;y;y>>=1,x=1LL*x*x%mod) if (y&1) ans=1LL*ans*x%mod; return ans; } int C( int x, int y){ if (y<0||y>x) return 0; return 1LL*Fac[x]*Inv[y]%mod*Inv[x-y]%mod; } int dp[N][N]; int main(){ n=read(); for ( int i=Fac[0]=1;i<=n;i++) Fac[i]=1LL*Fac[i-1]*i%mod; Inv[n]=Pow(Fac[n],mod-2); for ( int i=n;i>=1;i--) Inv[i-1]=1LL*Inv[i]*i%mod; memset (dp,0, sizeof dp); dp[1][1]=dp[1][0]=1; for ( int i=2;i<=n;i++) for ( int j=0;j<=n;j++) for ( int k=0;j+k<=n;k++){ int tmp=1LL*dp[i-1][j]*dp[i-1][k]%mod; dp[i][j+k]=(tmp+dp[i][j+k])%mod; dp[i][j+k]=(2LL*tmp*(j+k)+dp[i][j+k])%mod; dp[i][j+k+1]=(tmp+dp[i][j+k+1])%mod; dp[i][j+k-1]=(2LL*tmp*C(j+k,2)+dp[i][j+k-1])%mod; } cout << dp[n][1]; return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步