一道规律题
题目描述
cb是一个非常优秀的学长,他拥有一套自己心仪的卡牌,他将其命名为“小心心”卡牌。
cb的卡牌很独特,卡牌的面值都是2的次幂,比如1、2、4、8、16…等,你可以认为每个2的次幂的面值cb都有,并且每个面值的卡牌都只有2张。
现在cb得到了一项任务,他被要求用“小心心”卡牌来拼凑出总面值为n的卡牌集合。cb想知道他有多少种方法可以得到总面值为n。
输入
第一行一个整数T (0<T<1000)
接下来每行一个数字n (0<n<1000000)
输出
输出T行,每行为凑出n的方法总数
样例输入
2
1
2
样例输出
1
2
提示
第一个样例1只有一种拼凑方法,即 1
第二个样例2有两种拼凑方法,即2 与 1,1
Solution:用2的次幂凑数,也就是用二进制表示数。每两个低次幂的数的和即为高进制数:1+1=2,2+2=4,4+4=8。如果数字为16,即10000,则组合的方式为16,8+8,8+4+4,8+4+2+2,8+4+2+1+1,这五种写法;同时推到其他数字,如果1010,即10这个数字,二进制表示方法为8+2,所以我们将8与2的组合方式求出即可,注意处理8与2表示方法重合的部分,即如果8表示为4+2+2,则2只能为1+1。
//std
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int sum=0;//用sum来处理方案重叠的方法,并且sum记录的是不含当前位置为1的方案数的总和
int Max=1;//Max记录为已经处理过的以1开头的方案数
while(n)
{
if(n%2==0)
sum+=Max;
else
Max+=sum;
n/=2;
}
printf("%d\n",Max);
}
return 0;
}
dp做法:
dp[1]=1;
dp[2]=2;
for (int j=3;j<=1000000;j++)
{
if (j%2!=0)//j为奇数
dp[j]=dp[j-1]-dp[j-2];
else//j为偶数
dp[j]=dp[j-1]+dp[j/2];
}