P12415 「YLLOI-R1-T4」枫 绿 题解

Part0. 前言

好简单的 Div.3 T4。

赛时 AC 记录


Part1. 题意

给定一个 n × m n\times m n×m 的网格图,在其中构建一棵有根树,使得父节点一定在子节点上方,求可构建多少棵不同的有根树。


Part2. 思路

对于点 A ( i , j ) A (i,j) A(i,j),我们发现只要点 B ( x , y ) B (x,y) B(x,y) 满足 x < i x<i x<i,即可将 B B B 作为 A A A 的父节点。根据这一性质,我们发现对于第 i i i 行的所有点, 1 ∼ i − 1 1\sim i-1 1i1 行的所有点均可作为其父节点,而不用管位置关系。

因此,可设 f i , j f_{i,j} fi,j 表示当前考虑第 i i i 行、第 1 ∼ i 1\sim i 1i 行共有 j j j 个点在树上。因为每一行都能作为根节点所在的行,所以初始时 f i , 1 = m f_{i,1}=m fi,1=m

考虑转移。对于第 i i i 行、第 1 ∼ i − 1 1\sim i-1 1i1 行共有 j j j 个点在树上、第 i i i 行有 k k k 个点在树上的情况, f i , j + k f_{i,j+k} fi,j+k f i − 1 , j f_{i-1,j} fi1,j 转移而来、第 i i i 行的 k k k 个在树上的点可任选、其父节点也可任选,我们得到转移方程:

f i , j + k = ∑ j = 0 1 + ( i − 2 ) × m ∑ k = 0 m f [ i − 1 ] [ j ] × ( m k ) × j k f_{i,j+k}=\sum\limits_{j=0}^{1+(i-2)\times m}\sum\limits_{k=0}^{m} f[i-1][j]\times\binom{m}{k}\times j^k fi,j+k=j=01+(i2)×mk=0mf[i1][j]×(km)×jk

最终答案为 ∑ i = 1 n × m f n , i \sum\limits_{i=1}^{n\times m} f_{n,i} i=1n×mfn,i


Part3. 解释

枚举时 1 ≤ j ≤ 1 + ( i − 2 ) × m 1\le j\le 1+(i-2)\times m 1j1+(i2)×m 是因为 1 ∼ i − 1 1\sim i-1 1i1 行必有一行只有一个根节点,其它行不定,所以不用枚举至 ( i − 1 ) × m (i-1)\times m (i1)×m


Part4. 代码

为和思路保持一致,使用赛后修改的代码。

#include <bits/stdc++.h>
using namespace std;

namespace rab {
    const int N=81,mod=1e9+7;
    int n,m,ans,c[N][N],f[N][N*N];
    long long g;

    inline int ksm (int x,int y,int z=mod) {
        int rs=1;
        while (y) {
            if (y&1) rs=1ll*rs*x%z;
            x=1ll*x*x%z,y>>=1;
        }
        return rs;
    }

    inline int main () {
        cin>> n>> m;
        for (int i=0;i<=m;i++) {
            c[i][0]=1;
            for (int j=1;j<=i;j++)
                c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
        for (int i=1;i<=n;i++) f[i][1]=m;
        for (int i=2;i<=n;i++) {
            for (int j=0;j<=1+(i-2)*m;j++) {
                for (int k=0;k<=m;k++) {
                    g=1ll*f[i-1][j]*c[m][k];
                    if (g>=mod) g%=mod;
                    g=1ll*g*ksm (j,k);
                    if (g>=mod) g%=mod;
                    f[i][j+k]=(f[i][j+k]+g)%mod;
                }
            }
        }
        for (int i=1;i<=n*m;i++) ans=(ans+f[n][i])%mod;
        cout<< ans;
        return 0;
    }
}

int main () {
    ios::sync_with_stdio (0);
    cin.tie (0);cout.tie (0);
    return rab::main ();
}

完结撒花!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值