Processing math: 73%


Codeforces 830D Singer House 动态规划

原文链接https://www.cnblogs.com/zhouzhendong/p/CF830D.html

题解

考虑用 dp[i][j] 表示深度为 i 的树里,有 j 条路径的方案数。分四种情况转移即可:

枚举 j,k ,我们来算一下 dp[i1][j]dp[i1][k]dp[i] 的贡献。
tmp=dp[i1][j]×dp[i1][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;
}

  

posted @   zzd233  阅读(271)  评论(0编辑  收藏  举报

点击右上角即可分享
微信分享提示