Codeforces 382E Ksenia and Combinatorics 【组合计数】*

这篇博客讨论了Codeforces 382E问题,涉及如何解决关于有n个顶点的标记树,每个顶点最多连接三个其他顶点,且顶点1最多连接两个其他顶点,同时最大匹配数为k的树的数量。文章通过动态规划(DP)的方法进行计数,并给出了输入输出示例及解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Codeforces 382E Ksenia and Combinatorics


Ksenia has her winter exams. Today she is learning combinatorics. Here’s one of the problems she needs to learn to solve.

How many distinct trees are there consisting of n vertices, each with the following properties:

the tree is marked, that is, the vertices of the tree are numbered from 1 to n;
each vertex of the tree is connected with at most three other vertices, and at the same moment the vertex with number 1 is connected with at most two other vertices;
the size of the tree’s maximum matching equals k.
Two trees are considered distinct if there are such two vertices u and v, that in one tree they are connected by an edge and in the other tree they are not.

Help Ksenia solve the problem for the given n and k. As the answer to the problem can be very huge you should output it modulo 1000000007 (109 + 7).

Input

The first line contains two integers n, k (1 ≤ n, k ≤ 50).

Output

Print a single integer — the answer to the problem modulo 1000000007 (109 + 7).

Examples

input

1 1

output

0

input

2 1

output

1

input

3 1

output

3

input

4 2

output

12

Note

If you aren’t familiar with matchings, please, read the following link: http://en.wikipedia.org/wiki/Matching_(graph_theory).


简洁版题意:有n个节点的数,每个节点有不同的标号,求生成树匹配大小为k的方案数,其中除了根节点所有节点的度数不超过3,根节点1度数不超过2

考虑DP计数吧
dp[i][j][0/1] d p [ i ] [ j ] [ 0 / 1 ] 表示大小为i的子树,最大匹配是j,是否匹配当前节点的方案数
然后当i==n的时候和左右子树大小相同的情况需要特判掉

然后就是常规DP

#include<bits/stdc++.h>
using namespace std;
#define yyf 1000000007
#define N 60
#define LL long long
LL dp[N][N][2];
LL C[N][N];
void update(LL &a,LL b){a=(a+b)%yyf;}
int main(){
    LL n,k;scanf("%lld%lld",&n,&k);
    if(k*2>n){printf("0");return 0;}
    for(LL i=0;i<=n;i++)C[i][0]=1;
    for(LL i=1;i<=n;i++)
        for(LL j=1;j<=i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%yyf;
    dp[1][0][0]=dp[0][0][1]=1;
    for(LL siz=2;siz<=n;siz++)
        for(LL mac=1;mac<=k;mac++){
            //不匹配当前节点
            for(LL ls=0,rs=siz-1;ls<=rs;ls++,rs--){
                for(LL lm=0,rm=mac;lm<=mac;lm++,rm--){
                    if(lm*2>ls||rm*2>rs)continue;
                    LL tmp=(ls==rs?C[siz-2][ls-1]:C[siz-1][ls])*(siz==n?1:siz)%yyf;//特判掉左边大小等于右边
                    update(dp[siz][mac][0],dp[ls][lm][1]*dp[rs][rm][1]%yyf*tmp%yyf);
                }
            }
            //匹配当前节点
            for(LL ls=0,rs=siz-1;ls<=rs;ls++,rs--){
                for(LL lm=0,rm=mac-1;lm<mac;lm++,rm--){
                    if(lm*2>ls||rm*2>rs)continue;
                    LL tmp=(ls==rs?C[siz-2][ls-1]:C[siz-1][ls])*(siz==n?1:siz)%yyf;
                    update(dp[siz][mac][1],dp[ls][lm][1]*dp[rs][rm][0]%yyf*tmp%yyf);
                    update(dp[siz][mac][1],dp[ls][lm][0]*dp[rs][rm][1]%yyf*tmp%yyf);
                    update(dp[siz][mac][1],dp[ls][lm][0]*dp[rs][rm][0]%yyf*tmp%yyf);
                }
            }
        }
    printf("%lld",(dp[n][k][0]+dp[n][k][1])%yyf);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值