给定一颗满二叉树,任意两点间的花费为两点间节点的个数。
从1走到n[顺序走, 1 - 2 - 3 - 。。。 - n],问花费。
第一步当然是先画出满二叉树的图。
多枚举一些情况可以得出一些规律,尤其关于2的次幂的标号。
4 = 2^2;
8 = 2^3;
16 = 2^4; 3->4 step+=1; 4 = 2^2; 1 = 2-1;
7->8 step+=2; 8 = 2^3; 2 = 3-1;
15->16 step+=3; 16 = 2^4; 3 = 4-1;
这种题可以想出一般就两种大致思路,一是直接从a走到b得答案 , 另外一种就是【从1到b的步数】 - 【从1到a的步数】。
第二种方法比较好写。。。
比较容易得出 从 1 走到 最左边的这些编号为2^k次方的结点上的步数,
1->2 0
1->4 1
1->8 4
1->16 11
然后可以猜一下 k代表2的次幂, 然后 dp[k] = 2*dp[k-1] + i - 1; (貌似还有一种是dp[k] = 2*dp[k-1] + (i-2)*2 )
最后比如你求1->9 可以转换成 1->8 + (3 - 1) + dfs(9 - 8)
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mf(x) memset(x, inf, sizeof(x))
#define ms(x) memset(x, 0, sizeof(x))
#define ll long long
using namespace std;
const int N = 100004;
int n;
ll dp[32];
ll getans(int x){
if(x < 4) return 0;
int i;
ll ans;
for(i = 2; (1LL<<i) < x; i++);
if (x == (1LL<<i) )
return dp[i];
return (ll)(dp[i-1] + (i-2) + getans(x - (1LL<<(i-1))) );
}
int main(){
int a, b;
dp[0] = dp[1] = 0;
for(int i=2;i<=32;i++) dp[i] = dp[i-1]*2 + i-1;
scanf("%d%d", &a, &b);
if(a>b) swap(a, b);
printf("%lld\n", getans(b) - getans(a));
return 0;
}