做法:
- 其实一开始推东西,推的太细了反而里通解越来越远~ _(:з」∠)_
- 首先要满足最优解,我们可以把最大的左子树看成满二叉树,然后去想右子树是怎么构造的即可。这棵右子树,它的左右子树必定满足结点之差<=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;
}