蓝桥杯上升子序列(动态规划)

1. 问题描述:

给定一个序列 (a_1, a_2, …, a_n), 它的一个上升子序列是指从序列中取出一些元素,按照原来的顺序排列后,是单调递增的序列。
例如,对于序列 (3, 2, 7, 6, 7),取出下标为 2, 4, 5 的元素 a_2, a_4, a_5,即 2, 6, 7,是一个上升子序列。
在这个序列中,有 7 个长度为 2 的上升子序列,
例如
1. 下标 1, 3 对应的 3, 7;
2. 下标 1, 4 对应的 3, 6;
3. 下标 1, 5 对应的 3, 7;
4. 下标 2, 3 对应的 2, 7;
5. 下标 2, 4 对应的 2, 6;
6. 下标 2, 5 对应的 2, 7;
7. 下标 4, 5 对应的 6, 7。
注意,可能有下标不同但对应数值相同的上升子序列,他们应当算成不同的上升子序列。
给定序列,请问序列中一共有多少个长度为 k 的上升子序列。

输入格式
输入第一行包含两个整数 n, k,表示序列的长度和上升子序列的长度。
第二行包含 n 个整数 a_1, a_2, …, a_n,表示给定的序列。
输出格式
输出一行,包含一个整数,表示长度为 k 的上升子序列的数量,答案可能很大,请输出答案除以 1000007 的余数。
样例输入
5 2
3 2 7 6 7
样例输出
7

数据规模和约定
对于 30% 的评测用例,1 <= n <= 20, 0 <= a_i <= 100。
对于 50% 的评测用例,1 <= n <= 100, 0 <= a_i <= 1000。
对于所有评测用例,1 <= n <= 1000, 1 <= k <= 10, 0 <= a_i <= 10000。

2. 思路分析:

上升子序列的问题是经典的动态规划问题,一般求解上升子序列的问题中dp数组的含义是以nums[i]结尾的上升子序列的长度,因为这道题目需要求解的是长度为k的上升子序列的数目,所以我们可以在一维dp数组上增加多一维那么就可以表示以nums[i]结尾长度为k的上升子序列的数目,明确dp数组的含义之后接下来就好办了,使用三层循环进行dp数组的推导即可,最外层循环表示以当前的nums[i]结尾,第二层循环是通过尝试将nums[i]拼接到已经有的上升子序列后面构成更长的上升子序列,最后一个循环是用来计算以nums[i]结尾长度为(1...k)的上升子序列的数目

3. 代码如下:

if __name__ == '__main__':
    n, k = map(int, input().split())
    nums = list(map(int, input().split()))
    dp = [[0] * (k + 1) for i in range(n)]
    # 以nums[i]结尾长度为1的dp数组的数目
    for i in range(n):
        dp[i][1] = 1
    for i in range(n):
        for j in range(i):
            if nums[i] > nums[j]:
                # 以nums[i]结能够构成更长的上升子序列
                for k in range(2, k + 1):
                    # 在长度为k-1的基础上以当前的nums[i]结尾那么长度就变成了k
                    dp[i][k] = (dp[i][k] + dp[j][k - 1]) % 1000007
    count = 0
    for i in range(n):
        count = (count + dp[i][k]) % 1000007
    print(count)

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值