[树的状态的DP] URAL - 1117

给定一颗满二叉树,任意两点间的花费为两点间节点的个数。

从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;
}



猜你喜欢

转载自blog.csdn.net/khn64/article/details/80840820
今日推荐