标签:21 计数 cdot leftarrow int include 节点 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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。