模拟赛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,更新答案,最终将所有点在此高度下的情况前缀和更新

完结撒花

posted @ 2018-10-18 18:41  ASDIC减除  阅读(145)  评论(0编辑  收藏  举报