P12415 「YLLOI-R1-T4」枫 绿 题解
Part0. 前言
好简单的 Div.3 T4。
Part1. 题意
给定一个 \(n\times m\) 的网格图,在其中构建一棵有根树,使得父节点一定在子节点上方,求可构建多少棵不同的有根树。
Part2. 思路
对于点 \(A (i,j)\),我们发现只要点 \(B (x,y)\) 满足 \(x<i\),即可将 \(B\) 作为 \(A\) 的父节点。根据这一性质,我们发现对于第 \(i\) 行的所有点,\(1\sim i-1\) 行的所有点均可作为其父节点,而不用管位置关系。
因此,可设 \(f_{i,j}\) 表示当前考虑第 \(i\) 行、第 \(1\sim i\) 行共有 \(j\) 个点在树上。因为每一行都能作为根节点所在的行,所以初始时 \(f_{i,1}=m\)。
考虑转移。对于第 \(i\) 行、第 \(1\sim i-1\) 行共有 \(j\) 个点在树上、第 \(i\) 行有 \(k\) 个点在树上的情况,\(f_{i,j+k}\) 由 \(f_{i-1,j}\) 转移而来、第 \(i\) 行的 \(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
\]
最终答案为 \(\sum\limits_{i=1}^{n\times m} f_{n,i}\)。
Part3. 解释
枚举时 \(1\le j\le 1+(i-2)\times m\) 是因为 \(1\sim i-1\) 行必有一行只有一个根节点,其它行不定,所以不用枚举至 \((i-1)\times 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 ();
}
完结撒花!

浙公网安备 33010602011771号