1 条题解
-
0
题目大意
给定 个节点的树,保证父亲节点编号小于儿子,求有多少 个节点的树(根节点为 ),使得:
- 对于所有 ,在两棵树上 的标号相同。
- 对于所有 ,在新树上 。
数据范围:。
思路分析
考虑 如何做,不难发现第一个条件等价于 的虚树不变,因此只需要在原树上插入一个点,可以插在边中间或者挂在节点下面,方案数 。
对于 的一般情况,此时要求每个前缀的虚树都不包含更大的节点,从 依次插入每个节点,方案数 。
对于原问题,我们依然考虑依次插入 ,但是插入 时 可以不在 的虚树上,而是通过一个 挂上去,而这个 一定在 范围内。
因此对于每个 ,要么直接将插入树上,有 种方案,要么在 中另选择一个节点插在某条边中间,然后把 挂在该节点下面。
不难设计出一个 dp, 表示当前已经插入 , 中已经被插入的元素是集合 ,转移时如果 就跳过,否则按上述过程转移,注意此时树的大小是 。
时间复杂度:。
代码呈现
#include<bits/stdc++.h> #define ll long long using namespace std; const int MOD=1e9+7; int n,m,k,f[1<<10],pc[1<<10]; ll g[1<<10]; void solve() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<n;++i) scanf("%*d"); memset(f,0,sizeof(f)),memset(g,0,sizeof(g)); if(!k) { ll s=1; for(int i=n;i<n+m;++i) s=s*(2*i-1)%MOD; return printf("%lld\n",s),void(); } for(int i=1;i<(1<<k);++i) pc[i]=pc[i>>1]+(i&1); f[0]=1; for(int i=n;i<n+m;++i) { for(int s=0;s<(1<<k);++s) { if(s&1) g[s>>1]+=f[s]; else { int z=i+pc[s],t=s>>1; g[t]+=1ll*f[s]*(2*z-1); for(int j=0;j<k;++j) if(!(t>>j&1)) g[t|(1<<j)]+=1ll*f[s]*(z-1); } } for(int s=0;s<(1<<k);++s) f[s]=g[s]%MOD,g[s]=0; } printf("%d\n",f[0]); } signed main() { int c,T; scanf("%d%d",&c,&T); while(T--) solve(); return 0; }
- 1
信息
- ID
- 7290
- 时间
- 500ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 7
- 已通过
- 2
- 上传者