小明走楼梯
Description
小明来走楼梯啦! 众所周知小明有个怪癖,就是上楼梯的时候一步跨的台阶数一定是2的幂。
那么问题来了,对于一个有n个台阶的楼梯,小明有多少种不同的上楼梯的办法使得他刚好走完这个楼梯?
Input
第一行是一个正整数T,表示有T组测试数据。 每组测试数据有一行一个正整数n,表示楼梯的台阶数。
(1<=T<=50000,1<=n<=50000)
Output
每组数据输出一行,表示小明的上楼梯的方案的个数。 由于这个答案会很大,只要输出方案数对10000取模的答案即可。
Sample Input
4
1
2
3
4
Sample Output
1
2
3
6
C++代码:
#include<iostream>
#include<cmath>
using namespace std;
int fk[50001] = {0}; #将上楼梯的种类存在全局数组fk[]里,并将其初始化为0
int f(int n)
{
if (n == 0) #假设n=0时,fk[0]=1,这样后面当n=2^k时可以直接套用表达式,避免分情况讨论
{
fk[0] = 1;
return fk[0];
}
else if (n == 1) #n=1时当然只有一种方法
{
fk[1] = 1;
return fk[1];
}
else
{
if (fk[n] != 0) #当fk[n]不为0,即这一步已经算过时,则直接返回该值
{
fk[n] %= 10000;
return fk[n];
}
int item = int(log(n) / log(2)) + 1; #这里利用换底公式,计算出递归表达式应该由item个项组成
for (int k = 0; k < item; k++)
{
fk[n] += f(n - (1 << k)); #递归表达式
}
fk[n] %= 10000; #将最后结果取模
return fk[n];
}
}
int main()
{
int group;
cin >> group;
while (group > 0)
{
int n;
cin >> n;
cout << f(n) << endl;
group--;
}
system("pause");
return 0;
}
这道题的思路,跟一道很经典的也是小明爬楼梯的题很类似Climbing Stairs(话说小明真是人才,爬楼梯都有这么多种爬法~~)
这道题的思路,首先要列出递归表达式。
首先我们假设我们的小明同学已经走了好几步了,就差最后一步就能爬到n层台阶结束游戏。这样我们计算一下有几种这样的情况(差一步就能爬到n层)。因为一步只能跨2的幂次方阶台阶,所以这最后一步可以跨1,2,4,8,……,2^k,因为每一步都不能大于n,所以取k=log(n)。
因此我们有:f(n) = f(n-2^0) + f(n-2^1) + f(n-2^2) + …… + f(n-2^k)。
所以结果显而易见,剩下的就是想办法提高算法的效率。我这里没有多想,就简单的用一个数组保存起前面的数据,以达到空间换时间的想法。