题目链接: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;
}