1030 完美数列

1030 完美数列 (25 分)

题意描述:

给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。

现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。

输入格式:
输入第一行给出两个正整数 N 和 p,其中 N(≤10^​5​​ )是输入的正整数的个数,p(≤10^​9​​ )是给定的参数。第二行给出 N 个正整数,每个数不超过 10^​9​​ 。

输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。

输入样例:
10 8
2 3 20 4 5 1 6 7 8 9
输出样例:
8


解题思路:
根据题意,我们可以把题目的描述改为如下的形式:
给定一个升序数组,(我们可以对输入的数组排序得到一个升序数组),从数组中挑出连续的(连续是一个隐藏的条件,因为要想让子数组的长度最长,就要让min 和 max组成的区间覆盖原数组中尽可能多的元素,把min 到 max的所有元素都放置到子数组中就是连续的。)一部分组成一个子数组,这个子数组要满足 max <= min * p。 求所有满足要求的最长子数组的长度。

这道题目可以用动态规划的思路来求解,时间复杂度为O(n) ,这样应该就不会超时了。

我们用一个数组dynamic_planning来记录输入数组data中的每一个元素作为 一个完美数列的最大值的时候 这个完美数列的长度。如dynamic_planning[1] 表示以data[1] 作为某个完美数列的最大值的时候这个数列的长度。
当程序执行到 data[x] 的时候, 所有以data[x]左边的元素作为最大值的完美数列的长度都已经求解出来了。那么对于以data[x]为最大值的完美数列有两种可能:

  • 这个完美数列是data[x-1]的那个完美数列的扩展,这两个完美数列有着相同的最小值。此时 dynamic_planning[x] = dynamic_planning[x-1] + 1
  • 这个完美数列和data[x-1]的那个完美数列完全不同,最大值不同,最小值也不同。这时,我们需要找到一个新的最小值,然后求出这个最小值到data[x]这个最大值之间的元素数量。

最后,我们已经求出了所有可能的完美数列的长度,只要返回其中的最大值即可。


代码:


def main():
    N, p = (int(x) for x in input().split())
    # 元组拆包
    data = [int(x) for x in input().split()]
    # 接收输入的N个数字为整数列表
    data.sort()
    # 对输入的数字排序,排序结果为从小到大
    dynamic_planning = [1 for x in range(N)]
    # dynamic_planning用来记录data中的每一个元素作为 一个完美数列的最大值的时候 这个完美数列的长度。
    # 如dynamic_planning[1] 表示以data[1] 作为某个完美数列的最大值的时候这个数列的长度。

    minn_index = 0
    # 当前的完美数列的最小值下标
    minn = data[minn_index]
    # 当前完美数列的最小值
    for x in range(1, N):
        if data[x] <= p * minn:
            # 如果data[x]所在的完美数列和data[x-1]所在的完美数列有着相同的最小值
            dynamic_planning[x] = dynamic_planning[x - 1] + 1
        else:
            # 否则找到一个与data[x]相适应的,新的最小值来构造完美数列
            while data[x] > p * minn:
                # 最小值不断增大,直到 data[x] <= p * M,直到满足完美数列的约束。
                minn_index += 1
                minn = data[minn_index]
            dynamic_planning[x] = x - minn_index + 1
            # 然后更新,新的完美数列的长度。看,因为data是我们已经排过序的结果,所以要把min 到 max 的所有元素都放进来,只需要计算下标即可。
            # 这一段可能不好理解,建议大家手动执行一下就能体会动态规划的魅力了。
    # print(data)
    # print(dynamic_planning)
    print(max(dynamic_planning))
    # 输出所有完美数列的最大长度即可


if __name__ == '__main__':
    main()


易错点:

  • 直接暴力去做可能会超时。

总结:

  • 存储中间结果,减少重复计算是动态规划的魅力所在。

另:

四月将尽,项目受阻,心力交瘁,身心俱疲。后续题目将改为不定期更新,下次更新时间待定。
Iwillbeback
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值