题目链接:https://ac.nowcoder.com/acm/contest/940/A/
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

kotori共有n块糖果,每块糖果的初始状态是分散的,她想把这些糖果聚在一堆。但她每次只能把两堆糖果合并成一堆。
已知把两堆数量为a和b的糖果聚在一堆的代价是|a-b|。
kotori想知道,她把这n块糖果聚在一堆的最小代价是多少?

输入描述

第一行是一个正整数T,代表数据组数。
第二行到第T+1行,每行一个非负整数n,代表kotori的糖果总数量。

输出描述

每行一个整数,代表kotori需要花费的最小代价。

输入

2
5
6

输出

2
2

说明

n=5时,kotori可以这样聚集糖果:
1 1 1 1 1
2 1 1 1
2 2 1
2 3
5
每一步的代价分别是0,0,1,1,总代价为2。

备注

对于50%的数据,0<T≤100000, 0≤n≤100000
对于另外50%的数据,T=1, 0≤n≤1e18

解题思路

题意:合并,求最小代价值。
思路:将一个堆二分,递归求该堆合并的最小代价值。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll cnt[100005], n;
ll slove(ll x) {
    if (x <= 100000) {
        if (cnt[x])
            return cnt[x];
        if (x < 2 || !(x & (x - 1)))
            return cnt[x] = 0;
        if (x & 1)
            return cnt[x] = slove(x >> 1) + slove((x >> 1) + 1) + 1;
        return cnt[x] = slove(x >> 1) << 1;
    }
    if (x < 2 || !(x & (x - 1)))
        return 0;
    if (x & 1)
        return slove(x >> 1) + slove(x >> 1 + 1) + 1;
    return slove(x >> 1) << 1;
}
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%lld", &n);
        printf("%lld\n", slove(n));
    }
    return 0;
}