1001搬砖
Problem Description
小明现在是人见人爱,花见花开的高富帅,整天沉浸在美女环绕的笙歌妙舞当中。但是人们有所不知,春风得意的小明也曾有着一段艰苦的奋斗史。
那时的小明还没剪去长发,没有信用卡没有她,没有24小时热水的家,可当初的小明是那么快乐,尽管甚至没有一把破木吉他…
之所以快乐,是因为那时的小明心怀逆袭梦想。有一天,小明为了给他心目中的女神买生日礼物,来到了某建筑工地搬砖挣钱。就在这个时候,工地上又运来了一卡车的砖,包工头让小明把卡车卸下来的那堆砖分成一块一块的(要求任何2块转都要分开)。作为资深搬运工,小明总是每次将一堆砖分为两堆,这时候,所消耗的体力是分完之后两堆砖数目的差值。
现在,已知卡车运来的砖的数目,请告诉小明最少要花费多少体力才能完成包工头所要求的任务呢?
Input
输入数据第一行是一个正整数T(T<=100),表示有T组测试数据。
接下来T行每行一个正整数N(N<=10000000),表示卡车运来的砖块的数目。
Output
对于每组数据,请输出小明完成任务所需的最少体力数。
Sample Input
4
5
Sample Output
0
2
题意概述
把一个数a分成b+c,需要消耗abs(b-c)的精力。现需要把一个数n无限次数的分解成n个1,问:最少需要消耗多少精力?
题目分析
首先考虑到对于1,不需要分解,消耗为0。
对于2可以分解为1+1,消耗为0。
对于3可以分解为1+2,消耗为1的消耗+2的消耗+abs(1-2)。
……
动态规划:
设f(n)为分解n时的最小消耗,当n为偶数时,f(n)=2*f(n/2);当n为基数时,f(n)=f(n/2)+f(n/2+1)+1。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define INF 0x7ffffff
#define LOCAL
using namespace std;
int ans[10000001];
int main(){
#ifdef LOCAL
freopen("input.in","r",stdin);
#endif // LOCAL
int t;
for(int i=0;i<10000001;i++){
ans[i] = 0;
}
ans[1] = 0;
ans[2] = 0;
for(int i=3;i<10000001;i++){
if(i%2!=0) ans[i] = ans[i/2]+ans[i/2+1]+1;
else ans[i] = 2*ans[i/2];
}
cin>>t;
while(t--){