#21 CF830D
作者:互联网
Singer House
题目描述
解法
同时路径计数问题,本题可以和 环 这题对比起来理解。
基本方法都是一样的,首先考虑计数顺序应该是自底向上的树形 \(dp\),但是计数顺序却和我们考虑的状态——有向路径产生了冲突,因为按照这样的计数顺序,有向路径从某个点来看,可能就是若干个分散的有向链。
为了解决这样的冲突,我们在 \(dp\) 的过程中就需要维护一个有向链分散,合并的过程。这个过程的计数可以通过记录有向链的数量来实现,设 \(f_{n,k}\) 表示深度为 \(n\) 的子树内有 \(k\) 条有向链的方案数,转移:
- 不选根节点:\(f_{n,k}\leftarrow f_{n-1,i}\cdot f_{n-1,k-i}\)
- 让根节点成为单独的链:\(f_{n,k}\leftarrow f_{n-1,i}\cdot f_{n-1,k-i-1}\)
- 让根节点拼接一条链,可以选择成为起点或者成为终点:\(f_{n,k}\leftarrow f_{n-1,i}\cdot f_{n-1,k-i}\cdot (2k)\)
- 让根节点拼接两条链,方案是 \(A(k,2)\),因为有顺序:\(f_{n,k}\leftarrow f_{n-1,i}\cdot f_{n-1,k-i+1}\cdot (k+1)\cdot k\)
时间复杂度 \(O(n^3)\)
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 405;
const int MOD = 1e9+7;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,f[M][M];
int F(int n,int k)
{
if(!k) return 1;
if(n==1) return k==1;
if(~f[n][k]) return f[n][k];
int r=0;
for(int i=0;i<=k;i++)
r=(r+F(n-1,i)*F(n-1,k-i))%MOD;
for(int i=0;i<k;i++)
r=(r+F(n-1,i)*F(n-1,k-i-1))%MOD;
for(int i=0;i<=k;i++)
r=(r+2*k*F(n-1,i)%MOD*F(n-1,k-i))%MOD;
for(int i=0;i<=k+1;i++)
r=(r+k*(k+1)*F(n-1,i)%MOD*F(n-1,k-i+1))%MOD;
return f[n][k]=r;
}
signed main()
{
n=read();
memset(f,-1,sizeof f);
printf("%d\n",F(n,1));
}
标签:21,计数,cdot,leftarrow,int,include,节点,CF830D 来源: https://www.cnblogs.com/C202044zxy/p/16323248.html