[牛客]牛客国庆集训派对Day2 F.平衡二叉树 ---- 递推 or 记忆化搜索

版权声明:本文为博主原创文章,转载请预先通知博主(〃▽〃)。 https://blog.csdn.net/m0_37624640/article/details/83412675

题目传送门

做法:

  • 其实一开始推东西,推的太细了反而里通解越来越远~ _(:з」∠)_
  • 首先要满足最优解,我们可以把最大的左子树看成满二叉树,然后去想右子树是怎么构造的即可。这棵右子树,它的左右子树必定满足结点之差<=d,且左右之差为d的时候最优,那么递归定义其左子树dp[h-1],右子树dp[h-1-d]。
  • 我们发现d>=h时,f[h] = h 为最优解。
  • 于是有了以下递推式:

在这里插入图片描述

AC代码: 递推写法

#include<bits/stdc++.h>
using namespace std;

#define IO          ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb(x)       push_back(x)
#define sz(x)       (int)(x).size()
#define sc(x)       scanf("%d",&x)
#define abs(x)      ((x)<0 ? -(x) : x)
#define all(x)      x.begin(),x.end()
#define mk(x,y)     make_pair(x,y)
#define fin         freopen("in.txt","r",stdin)
#define fout        freopen("out.txt","w",stdout)

typedef long long ll;
const int mod = 1e9+7;
const int maxm = 1e8+5;
const int maxn = 1e4+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 1ll<<62;

ll dp[maxn];
int main()
{
//    fin;
    IO;
    int n,d;
    while(cin>>n>>d)
    {
        if(n<=1){
            cout<<0<<endl;
            continue;
        }
        ll ans1 = (1ll<<(n-1))-1;
        for(int i=0;i<=d;i++) dp[i] = i;  //h<=d dp[i] = i
        for(int i=d+1;i<=n-1-d;i++) dp[i] = dp[i-1]+dp[i-1-d]+1;
        cout<<ans1-dp[n-1-d]<<endl;
    }
    return 0;
}

AC代码: 递归写法(记忆化) %%超霸

#include<bits/stdc++.h>
using namespace std;

#define IO          ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb(x)       push_back(x)
#define sz(x)       (int)(x).size()
#define sc(x)       scanf("%d",&x)
#define abs(x)      ((x)<0 ? -(x) : x)
#define all(x)      x.begin(),x.end()
#define mk(x,y)     make_pair(x,y)
#define fin         freopen("in.txt","r",stdin)
#define fout        freopen("out.txt","w",stdout)

typedef long long ll;
typedef pair<int,int> P;
const int mod = 1e9+7;
const int maxm = 1e8+5;
const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 1ll<<62;

ll dp[maxn];

int n,d;
ll dfs(int h)
{
    if(h<1) return 0;
    if(h<=d) return h;
    if(dp[h]) return dp[h];
    int l = h-1;
    int r = h-1-d; 
    dp[l] = dfs(l);
    dp[r] = dfs(r);
    return dp[l]+dp[r]+1;//左子树、右子树、根节点
}

int main()
{
    // fin;
    IO;
    cin>>n>>d;
    ll ans1 = (1ll<<(n-1))-1;
    ll ans2 = dfs(n-1-d);
    cout<<ans1-ans2<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37624640/article/details/83412675