由1e18的数据范围分析知,用优先队列的方法的时间复杂度为n,显然超时,所以这题采用分治的做法(简而言之,二分加递归时间复杂度为log2n
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,ll>a;
ll suan(ll n){
if(a[n])return a[n];//递归结束,有值的时候返回该值
if(n<=2)return 0;//由分析知,n<=2时怎么合并代价都是0
if(n%2==0)a[n]=2*suan(n/2);//如下所示,当n为偶时,可分为两个相同的值,递归该俩值,不花费代价
else a[n]=suan(n/2)+suan(n/2+1)+1;//当n为奇时,可分为两个相差1的一奇一偶的数,耗费代价为差值即1,继续递归
return a[n];
}
/*//将合并反向分析成划分
6
/\
3 3
/ \ / \
1 2 1 2
/\ /\
1 1 1 1
*/
int main(){
int t;
cin>>t;
while(t--){
ll n;
cin>>n;
cout<<suan(n)<<endl;
}
return 0;
}