bzoj3057 圣主的考验(树形dp+优化)

本文介绍了一种DP算法的优化方法,特别适用于特定类型的题目。通过计算不同深度下的最大和最小节点数来减少状态转移的时间复杂度,避免超时。文章还提到了输出格式的注意事项,并附带了一个完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实质上可以根据这道题的特性,把dp优化下,简直黑科技。处理出深度为d时,可能的最大节点数和最小节点数,这样转移就不会T了。。。还要注意这题输出贼坑,本来不少于九位的要输出前导0。。打表看一下分界点在38.。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 3010
#define mod 1000000000
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,dp[N][N],mx[N],mn[N],ans[N],d;
int main(){
//  freopen("fin.in","r",stdin);
    mx[1]=mn[1]=1;dp[0][0]=1;dp[1][1]=1;
    for(d=2;d;d++){//mn[d],深度为d,满足要求的树的最小节点数 
        mn[d]=mn[d-1]+mn[d-2]+1;if(mn[d]>3000) break;
        mx[d]=mx[d-1]+mx[d-1]+1;if(mx[d]>3000) mx[d]=3000;
        for(int i=mn[d];i<=mx[d];++i)
            for(int j=mn[d-1];j<=mx[d-1]&&j<i;++j){
                dp[i][d]=((ll)dp[j][d-1]*dp[i-1-j][d-2]*2+dp[i][d])%mod;
                dp[i][d]=(dp[i][d]+(ll)dp[j][d-1]*dp[i-1-j][d-1])%mod;
            }
    }
    for(int i=1;i<=3000;++i)
        for(int j=1;j<=d;++j) ans[i]=(ans[i]+dp[i][j])%mod;
    while(1){
        scanf("%d",&n);if(!n) break;
        if(n>=38) printf("%09d\n",ans[n]);
        else printf("%d\n",ans[n]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值