模拟赛20181016 dp
给出1-n的序列插入一个bst;
给出T组询问,包含n,h分别代表点数为n,高度为h的树,求所有插入顺序的合法方案数,模1e9+7
样例输入
1
2 1
样例输出
2
#include<bits/stdc++.h> #define LL long long #define rep(i,x,y) for(register int i=x;i<=y;i++) using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} const int N=510; const int mod=1000000007; LL C[N][N],f[N][N],g[N]; int T; int main(){ freopen("bst.in","r",stdin); freopen("bst.out","w",stdout); int nn=500,hh=500; rep(i,0,nn) C[i][0]=1;C[1][1]=1; rep(i,2,nn)rep(j,1,i) C[i][j]=1LL*(C[i-1][j-1]+C[i-1][j])%mod; memset(g,0,sizeof g); memset(f,0,sizeof f); f[1][1]=g[0]=1; rep(i,1,hh){ rep(j,1,nn)if(f[i][j])rep(k,0,nn-j-1) f[i+1][j+k+1]=(f[i+1][j+k+1]+1LL*f[i][j]*(g[k]*2+f[i][k])%mod*C[j+k][j]%mod)%mod; rep(j,1,nn) g[j]=(g[j]+f[i][j])%mod;} T=read();while(T--){ int n=read(),h=read(); printf("%lld\n",f[h+1][n]);} return 0;}
我们考虑点数n+1,我们发现序列内部的顺序并没有什么卵用,而且树的形状发现有递归的情况
那么dp[i][j] 代表 高度为i点数为j 的方案数
刷表法更加好用,所以转移方程可以转化为
dp[i+1][j+k+1]+=dp[i][j]*dp[i(0-i)][k]*C[j+k][j]
我们发现两个子树中至少有一个的高度是h,剩下一个需要利用前缀和保存以平衡复杂度
那么大力枚举高度i,并更新点j由1-n,更新答案,最终将所有点在此高度下的情况前缀和更新
完结撒花