[每日算法]台阶问题


题目描述

N级的台阶,你一开始在底部,每次可以向上迈最多K级台阶(最少11级),问到达第NN级台阶有多少种不同方式。

输入格式

两个正整数N,K。

输出格式

一个正整数,为不同方式数,由于答案可能很大,你需要输出ans mod 100003后的结果。

输入输出样例

样例#1 输出#1
5 2 8
98765 89 86214

说明/提示

对于20%的数据,有N ≤ 10, K≤3;

对于40%的数据,有N≤1000;

对于100%的数据,有N ≤ 100000,K ≤ 100。

题解

根据N与K的值,列举一些具体的答案。

横坐标为总台阶数N,纵坐标为每次能走的最大步数K。

1 2 3 4 5 6 7 8
1 1 1 1 1 1 1 1 1
2 1 2 3 5 8 13 21 34
3 1 2 4 7 13 24 44 81
4 1 2 4 8 15 29 56 108
5 1 2 4 8 16 31 61 120

通过观察可以发现这个问题其实是一个变相的斐波那契数列。

解法1

用递归的思想来做,假设因为最大的步数为K,楼梯步数为N时的走法有aN种,那么最后走1步时,这步之前的走法有aN-1种;最后走2步时,这步之前的走法有aN-2种….最后走K步时,这步之前有a这步之前的走法有aN-K种,所以说楼梯步数为N时的走法数量为aN-1+aN-2+…+aN-K
因此只需要根据最大的步数K将阶梯数为1,2…K的总数分别写下来,即先初始化斐波那契数列前面的K项,接下来的项数只需要将前K项相加得到该项的总数。经过观察可以发现前面K项是有一个首项为1,公比为2的等比数列。因此程序先使用一个for循环将前K项初始化,由于加数的个数为K是个变量,这时候需要一个双重循环重置K项以后的项,第一重循环为处理的第i项,第二重循环是分别加这项前面的N项。返回最后一项的结果即可,时间复杂度为O(NK)。

解法2

解法1虽然思路比较清晰,但是代码实现相对麻烦一点,时间复杂度也比较大,通过整理解法1的数学公式,稍加推导就可以得到简化的公式:
当K=1时,无论台阶数有多少,都只能一次走一步,因此只有一种走法。

当K≠1,发现当i≤K时,有ai=2ai-1(即当前项为前一项的两倍);
i>K时,有ai=aN-1+aN-2+…+aN-K=2
ai-1-ai-1-K
与解法1相比,只需要初始化第一项为1,接下来只需要执行循环,如果i≤K,就为前一项的2倍,如果i>K,就为前一项的倍减去第i-1*-K项。返回最后一步的结果即可,时间复杂度为O(n)。

解法2源代码

#include <iostream>
using namespace std;

int main()
{
    //获取台阶的级数N和最大的步数K
    int N, K;
    int i = 0;
    cin >> N >> K;
    //为结果创建一个大小为N的动态数组
    int* result = new int[N];
    if (N < 1 || K < 1)
    {//先检查输入的数是否合法
        cout << "请输入大于0的整数!" << endl;
        return 0;
    }

    //初始化第0项和第一项为0
    result[0] = result[1] = 1;

    if (K == 1)
    {如果最大步数为1,那么级数为多少结果都为1
        cout << "1" << endl;
        return 0;
    }

    //注意避免出现负数,结果的数字可能比较大,需要mod100003
    for (i = 2;i <= N;i++)
    {
        if (i <= K)
        {//i<=K时为前一项的两倍
            result[i] = (2 * result[i - 1]) % 100003;
        }
        else
        {//i>K时为前一项的两倍减去第i-1-K项
            result[i] = (2 * result[i - 1]-result[i-1-K]) % 100003;
        }
    }

    cout << (result[N]+100003)%100003 << endl;

    return 0;
}

文章作者: 陈细利
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 陈细利 !
评论
 上一篇
[每日算法]快速排序 [每日算法]快速排序
题目描述利用快速排序算法将读入的 N 个数从小到大排序后输出。 快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成。(C++ 选手请不要试图使用 STL,虽然你可以使用 sort 一遍过
2021-03-08
下一篇 
计算机网络UDP套接字编程 计算机网络UDP套接字编程
1、UDP的服务器编程步骤:①.创建一个socket,用函数socket()②.绑定IP地址、端口等信息到socket上,用函数bind()③.循环接收数据,用函数recvfrom()④.关闭网络连接2、UDP的客户端编程步骤:①.创建一个
  目录